Skip to content

feat(mailtrap): add Mailtrap email, contacts, and email logs integration - #7564

Open
dr-3lo wants to merge 2 commits into
simstudioai:mainfrom
dr-3lo:feat/mailtrap-tool
Open

feat(mailtrap): add Mailtrap email, contacts, and email logs integration#7564
dr-3lo wants to merge 2 commits into
simstudioai:mainfrom
dr-3lo:feat/mailtrap-tool

Conversation

@dr-3lo

@dr-3lo dr-3lo commented Sep 7, 2026

Copy link
Copy Markdown

Summary

Adds a Mailtrap integration alongside the existing email integrations (agentmail, mailgun, resend, sendgrid, smtp, gmail).

Tools (apps/sim/tools/mailtrap/, 12):

  • send_email — transactional / bulk / sandbox stream; text, HTML or template body;
    cc/bcc/reply-to, category, custom variables, custom headers
  • Contacts: create_contact, get_contact, update_contact, delete_contact
  • Contact lists: list_contact_lists, create_contact_list, get_contact_list,
    update_contact_list, delete_contact_list
  • Email logs: list_email_logs, get_email_log — curated filter set with fixed
    operators (subject match contain/equal/empty; status/category/stream take a
    comma-separated any-of list). Negation, event, open/click-count and IP/domain
    filters are intentionally out of scope for the first version.

All tools call the Mailtrap API directly over the shared tool transport with token-scoped Bearer auth. Shared response mappers and output schemas live in types.ts / utils.ts. A mailtrap-errors extractor normalizes both the sending
API ({success, errors[]}) and the account API ({error} / {errors}) envelopes.

Block / icon / catalog: MailtrapBlock + MailtrapBlockMeta, theme-aware MailtrapIcon, regenerated tool metadata and docs, synced integration catalog.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation (generated integration page + intro section)
  • Other: ___________

Testing

Automatedapps/sim/tools/mailtrap/mailtrap.test.ts, 61 cases:

  • address parsing ("Name <email>", comma lists, quotes), id-list and JSON-record parsing
  • send_email stream routing (transactional/bulk/sandbox host + sandbox-id path), invalid stream / missing sandbox id / empty subject / missing body guards, template-only send, recipient parsing across to/cc/bcc
  • email-logs deep-object query building — subjectMatch contain/equal/empty, comma-separated status/category sent as value[], empty-CSV drop, URL encoding
  • response normalization for every tool (contacts, lists, logs) incl. malformed / empty / non-JSON bodies
  • the mailtrap-errors extractor across its three envelope shapes
  • a transformResponse cohort invariant asserting all 12 tools tolerate an empty and a non-JSON 200 body

Run: cd apps/sim && bunx vitest run tools/mailtrap/mailtrap.test.ts

Repo checks (green): type-check, biome, tool-metadata:check, docs:check, check:canvas-sentences, check:tool-request-boundary, check:api-validation, check:bare-icons.

Manual — against a real Mailtrap account on a local instance:

  • sent a transactional email; sent one through the sandbox stream with reply-to / cc / category set
  • listed contact lists; created a list, then deleted it
  • created a contact, get contact, then deleted it
  • get contact\list, update contact\list, delete contact\list with a non-existent id → 404 handled and surfaced

Reviewer focus:

  • error-extractor ordering in apps/sim/tools/error-extractors.ts
  • the shared output-schema constants in types.ts (pattern mirrors tools/harmonic/types.ts)

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

Screenshots/Videos

Screenshot 2026-09-07 at 14 09 43 Screenshot 2026-09-07 at 14 17 04 Screenshot 2026-09-07 at 14 23 28

@vercel

vercel Bot commented Sep 7, 2026

Copy link
Copy Markdown

@dr-3lo is attempting to deploy a commit to the Sim Team on Vercel.

A member of the Team first needs to authorize it.

@greptile-apps

greptile-apps Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR adds a complete Mailtrap integration for sending email, managing contacts and contact lists, and querying email logs. The latest changes address prior review feedback by:

  • Rejecting unbalanced recipient quotes and angle brackets without breaking quoted comma handling.
  • Applying stricter bare-email validation.
  • Requiring endpoint-defining response payloads before mapping successful results.
  • Adding regression coverage for malformed recipient lists and incomplete response envelopes.
  • Registering the integration across the Sim block catalog, generated tool metadata, documentation, and deployment configuration.

Confidence Score: 5/5

The PR appears safe to merge; the latest changes fully address the reviewed recipient-parsing and malformed-response concerns without introducing a new actionable defect.

Recipient tokenization now rejects unmatched delimiters and validates complete bare addresses, while response transforms require each endpoint’s defining nested payload or identifier before reporting success. All previous findings are resolved, and no new repository-rule violation or blocking behavior remains.

Important Files Changed

Filename Overview
apps/sim/tools/mailtrap/utils.ts Adds balanced-delimiter checks, stricter address validation, and endpoint payload assertion helpers; the reviewed changes correctly address the prior parser and malformed-response concerns.
apps/sim/tools/mailtrap/mailtrap.test.ts Adds focused regressions for unbalanced recipient syntax and missing defining response payloads.
apps/sim/tools/mailtrap/get_email_log.ts Requires a non-empty message identifier before returning a successful normalized email-log result.
apps/sim/tools/mailtrap/list_email_logs.ts Requires the response’s messages slice to be an array before mapping paginated email logs.
apps/sim/tools/mailtrap/create_contact.ts Requires the nested contact payload to exist before mapping a successful create response.
apps/sim/tools/mailtrap/update_contact.ts Requires the nested contact payload to exist before mapping a successful update response.
apps/sim/tools/mailtrap/get_contact.ts Requires the nested contact payload to exist before mapping a successful lookup response.
apps/sim/tools/mailtrap/create_contact_list.ts Validates that successful single-list responses include a numeric list identifier.
apps/sim/tools/mailtrap/get_contact_list.ts Validates that retrieved contact-list responses include their defining numeric identifier.
apps/sim/tools/mailtrap/update_contact_list.ts Validates the defining list identifier before returning an updated contact list.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    W[Sim workflow] --> B[Mailtrap block]
    B --> S[Send email]
    B --> C[Contacts]
    B --> L[Contact lists]
    B --> E[Email logs]
    S --> T[Transactional API]
    S --> U[Bulk API]
    S --> X[Sandbox API]
    C --> A[Mailtrap account API]
    L --> A
    E --> A
    T --> V[Validated response mapping]
    U --> V
    X --> V
    A --> V
    V --> O[Structured tool output]
Loading

Reviews (3): Last reviewed commit: "fix(mailtrap): validate nested payloads ..." | Re-trigger Greptile

Comment thread apps/sim/tools/mailtrap/utils.ts Outdated
Comment thread apps/sim/tools/mailtrap/utils.ts Outdated
Comment thread apps/sim/tools/mailtrap/utils.ts
Comment thread apps/sim/tools/mailtrap/index.ts Outdated
Add Mailtrap alongside the existing email integrations (agentmail, mailgun,
resend, sendgrid, smtp, gmail).

Tools (apps/sim/tools/mailtrap/, 12):
- send_email — transactional, bulk, or sandbox stream; text/HTML/template
  body, cc/bcc/reply-to, category, custom variables, custom headers
- create_contact / get_contact / update_contact / delete_contact
- list_contact_lists / create_contact_list / get_contact_list /
  update_contact_list / delete_contact_list
- list_email_logs / get_email_log — curated filter set with fixed operators
  (subject match contain/equal/empty; status/category/stream accept a
  comma-separated any-of list); negation, event, open/click count, and
  IP/domain filters are intentionally not exposed yet

All tools call the Mailtrap API directly over the shared tool transport,
token-scoped Bearer auth. Shared response mappers and output schemas live
in types.ts / utils.ts. A mailtrap-errors extractor normalizes the
sending API ({success,errors[]}) and account API ({error}/{errors})
error envelopes.

Block, icon, and catalog:
- MailtrapBlock + MailtrapBlockMeta (blocks/blocks/mailtrap.ts), registered
  in blocks/registry-maps.ts
- theme-aware MailtrapIcon (components/icons.tsx)
- regenerated tools/generated/{tool-ids,tool-metadata,tool-outputs}.ts
- generated docs page (apps/docs) + synced icon maps, meta.json, and
  packages/deployment-config integrations.json

Tests: apps/sim/tools/mailtrap/mailtrap.test.ts covering address
parsing, stream routing, filter query building, response normalization,
the error extractor, and a transformResponse cohort invariant.
@dr-3lo
dr-3lo force-pushed the feat/mailtrap-tool branch from 70aa23e to 46c62f8 Compare September 7, 2026 12:14
@dr-3lo

dr-3lo commented Sep 7, 2026

Copy link
Copy Markdown
Author

@greptileai the fixes force-pushed: amended the single commit with the review fixes.

  • Address parsing — split the recipient string on top-level commas only, so a quoted display name with a comma ("Doe, Jane" <jane@x.com>) stays one recipient; reject an entry with no @ locally.
  • Contact-list ids — keep an entry only if the whole trimmed value is digits; 12abc is dropped, not truncated to 12.
  • unsubscribedupdate_contact now coerces a string "true"/"false" instead of silently ignoring it.
  • Response handlingreadJsonBody/readJsonArray reject an empty, non-JSON, or wrongly-shaped 2xx body; send_email fails when a 2xx body doesn't confirm the send.
  • Importsindex.ts and the test file now use absolute @/tools/mailtrap/* paths.

Comment thread apps/sim/tools/mailtrap/utils.ts
…ters

Response payloads (utils.ts + read transforms):
- add expectRecord / expectArray / expectContactList / expectSendingMessage
- get/create/update_contact require the `data` object; the contact-list
  transforms require a numeric `id`; get_email_log requires a `message_id`;
  list_email_logs requires a `messages` array
- a well-formed 2xx body that is missing its defining slice ({} on
  get_contact, { "messages": "bad" } on list_email_logs) now fails instead
  of producing a fabricated empty result
- the list transforms keep the lenient per-row mappers, so one bad row
  does not drop the whole page

Recipient tokenizer (utils.ts):
- splitAddressEntries throws on an unbalanced quote or angle bracket
  instead of running to the end of the string and absorbing every
  following recipient into one entry
- each address is checked against a bare-address pattern
  (/^[^\s"<>,@]+@[^\s"<>,@]+$/) rather than a bare "contains @" test, so a
  value carrying spaces, commas, or brackets is rejected
@dr-3lo

dr-3lo commented Sep 7, 2026

Copy link
Copy Markdown
Author

@greptileai

Made changes to address your concerns:

Response payloads (utils.ts + read transforms):

  • add expectRecord / expectArray / expectContactList / expectSendingMessage
  • get/create/update_contact require the data object; the contact-list
    transforms require a numeric id; get_email_log requires a message_id;
    list_email_logs requires a messages array
  • a well-formed 2xx body that is missing its defining slice ({} on
    get_contact, { "messages": "bad" } on list_email_logs) now fails instead
    of producing a fabricated empty result
  • the list transforms keep the lenient per-row mappers, so one bad row
    does not drop the whole page

Recipient tokenizer (utils.ts):

  • splitAddressEntries throws on an unbalanced quote or angle bracket
    instead of running to the end of the string and absorbing every
    following recipient into one entry
  • each address is checked against a bare-address pattern
    (/^[^\s"<>,@]+@[^\s"<>,@]+$/) rather than a bare "contains @" test, so a
    value carrying spaces, commas, or brackets is rejected

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant