add-contact-to-segment
Add a contact to a segment in Resend (by contact ID or email).
Run a Resend account from an agent: send and read mail, manage contacts and segments, build broadcasts, verify domains, and read the API logs.
The plugin Resend Skills includes connection settings for this server.
LABSCO SUMMARY
Sending is the small half. What makes this worth wiring up is everything around a send: domain verification, suppression hygiene, segment membership, and request logs carrying full request and response bodies, so an agent chasing a delivery problem reads the actual API exchange instead of guessing at it. The hosted endpoint takes OAuth and installs nothing, which is the right default for web clients; the local build exists for CI and headless agents.
Resend's own MCP server for its email platform, hosted by Resend at https://mcp.resend.com/mcp and published on npm as resend-mcp if you would rather run the same open-source code yourself. Coverage goes well past sending: inbound mail, templates, contacts, broadcasts, automations, domains, suppressions, webhooks, and request logs.
A Resend account. On the hosted endpoint your client opens a browser to log in and approve access over OAuth; where a browser is not possible, pass a Resend API key as a Bearer token instead. Running it yourself needs an API key and a verified domain: npx -y resend-mcp over stdio with RESEND_API_KEY set, or npx -y resend-mcp --http --port 3000 to serve Streamable HTTP at /mcp, where each connecting client supplies its own key. SENDER_EMAIL_ADDRESS sets a default from-address; without one the server asks for a sender on every call. Behind a reverse proxy, --host or --allowed-hosts widens the localhost Host check that otherwise answers 403.
One command plus a key — npx add-mcp resend-mcp --name resend --env "RESEND_API_KEY=<YOUR_RESEND_API_KEY>"
USE CASES
Find the message, read its delivery state, then open the underlying API request and response for the send.
Create the domain, read back the records it needs, and trigger verification once DNS has propagated.
Define the segment, build the broadcast against it, send, then read who opened and what they clicked.
Add the address to the suppression list and confirm it is there, so nothing else reaches it.
List what came in, open the message and its attachments, and reply from the same session.
Counted once with only startup setup. Other versions, modes or optional credentials may expose a different list.
add-contact-to-segmentAdd a contact to a segment in Resend (by contact ID or email).
add-suppressionAdd an email address to the suppression list in Resend. Suppressed addresses never receive emails from the account, even when included as recipients. Hard bounces and spam complaints are added to the suppression list automatically; use this tool to manually suppress an address when needed, e.g. to honor a do-not-contact request. To suppress many addresses at once, use batch-add-suppressions instead.
batch-add-suppressionsAdd multiple email addresses to the suppression list in Resend in a single call. Suppressed addresses never receive emails from the account. Hard bounces and spam complaints are added to the suppression list automatically; use this tool to manually suppress addresses when needed, e.g. to honor do-not-contact requests. For a single address, use add-suppression instead.
batch-remove-suppressionsRemove multiple entries from the suppression list in Resend in a single call, by email addresses or by suppression IDs (provide exactly one of the two). The addresses will start receiving emails again. Before using this tool, you MUST double-check with the user that they want to remove these suppressions. Reference the EMAIL ADDRESSES (or IDs) when double-checking, and warn the user that addresses suppressed due to a bounce or complaint may hurt deliverability if emailed again. You may only use this tool if the user explicitly confirms they want to remove the suppressions after you double-check.
cancel-emailCancel a scheduled email that has not yet been sent. Only works for emails that were scheduled using the scheduledAt parameter.
compose-broadcastPurpose: Set the TipTap JSON content of a broadcast, enabling it to be edited visually in the Resend dashboard editor. Automatically connects and disconnects from the editor. Can also update metadata (subject, preview text, name) in the same call.
This is the recommended way to set email content. Content set via compose-broadcast can be visually edited by the user in the dashboard. Use this for newsletters and any broadcast where the user may want to refine the content.
Workflow: get-tiptap-json-content (with include_schema: true) → compose-broadcast
When to use:
Important: Always call get-tiptap-json-content first to retrieve the existing TipTap JSON, then build your changes on top of it. Skipping this will overwrite all existing content.
Note: Switching between compose (TipTap) and update (raw HTML) modes is lossy — some content or formatting may be lost. If the broadcast already has HTML content, ask the user before switching to compose mode.
compose-templatePurpose: Set the TipTap JSON content of a template, enabling it to be edited visually in the Resend dashboard editor. Automatically connects and disconnects from the editor. Can also update metadata (subject, name) in the same call.
This is the recommended way to set email content. Content set via compose-template can be visually edited by the user in the dashboard.
Workflow: get-tiptap-json-content (with include_schema: true) → compose-template
When to use:
Important: Always call get-tiptap-json-content first to retrieve the existing TipTap JSON, then build your changes on top of it. Skipping this will overwrite all existing content.
Note: Switching between compose (TipTap) and update (raw HTML) modes is lossy — some content or formatting may be lost. If the template already has HTML content, ask the user before switching to compose mode.
connect-to-editorPurpose: Show agent presence in the Resend dashboard editor. Users will see an agent avatar while connected.
When to use:
Returns: Connection token and room ID.
create-api-keyCreate a new API key in Resend. The token is only shown once upon creation, so you MUST display it to the user.
create-automationPurpose: Create an automation workflow that triggers on events and executes a sequence of steps.
When to use:
Workflow: manage-events (create event, if needed) → list-templates (to get template IDs) → get-template (to check if template has "from" and "subject" — if not, use list-domains to pick a verified domain for the step config) → create-automation → send-event (to test)
Returns: Automation ID and dashboard link.
The workflow is a JSON object with one key: "steps" — an array of step objects.
Each step has: key (unique string), type, config, and either "next" (string|null) or "branches" (for branching steps). Use keys like: "trigger", "send_email_1", "delay_1", "condition_1", "wait_event_1".
Step types
trigger — starts the automation when an event fires (required, exactly one)
config: { "eventName": "<event_name>" } Uses "next".
send_email — send an email using a published template
config: { "template": { "id": "<template_id>", "variables": { "<key>": "<value>" } }, "from": "Name <sender@example.com>", "subject": "Email subject", "replyTo": "<address>" } "from" and "subject" are resolved from the step config first, then fall back to the template. If neither provides a "from", the email will silently fail to send. If neither provides a "subject", the run will error. Best practice: always set "from" and "subject" on the step config so the automation is self-contained. Use list-domains to find verified domains for "from". "replyTo" and "variables" are optional. Variables can use { "var": "event.<field>" } or { "var": "contact.<field>" } for dynamic values. Uses "next".
delay — pause the workflow
config: { "duration": "<human-readable>" } Examples: "30 minutes", "1 hour", "2 days", "1 week". Max 30 days. Uses "next".
condition — conditional split based on contact or event data
config: A condition rule object: Single rule: { "type": "rule", "field": "event.<field>" or "contact.<field>", "operator": "<op>", "value": <value> } Compound: { "type": "and"|"or", "rules": [<rule>, ...] } Operators: eq, neq, gt, gte, lt, lte, contains, starts_with, ends_with, exists, is_empty. exists/is_empty do not require a value. Uses "branches": { "condition_met": "<step_key>", "condition_not_met": "<step_key_or_null>" }
wait_for_event — pause until a specific event arrives or timeout
config: { "eventName": "<event_name>", "timeout": "<human-readable>", "filterRule": <optional condition rule> } For email lifecycle events use "resend:email.<opened|clicked|bounced|delivered|complained|failed|suppressed>". Uses "branches": { "event_received": "<step_key>", "timeout": "<step_key_or_null>" }
contact_update — update contact fields
config: { "firstName": "<value>", "lastName": "<value>", "unsubscribed": true|false, "properties": { "<key>": "<value>" } } All fields optional. Values can use { "var": "event.<field>" } for dynamic data. Uses "next".
contact_delete — remove the contact from the audience
config: {} Uses "next".
add_to_segment — add contact to a segment
config: { "segmentId": "<segment_id>" } Uses "next".
Rules
Example: Linear drip campaign
{ "steps": [ { "key": "trigger", "type": "trigger", "config": { "eventName": "user.created" }, "next": "send_email_1" }, { "key": "send_email_1", "type": "send_email", "config": { "template": { "id": "tmpl_123" }, "from": "Welcome <hello@example.com>", "subject": "Welcome!" }, "next": "delay_1" }, { "key": "delay_1", "type": "delay", "config": { "duration": "3 days" }, "next": "send_email_2" }, { "key": "send_email_2", "type": "send_email", "config": { "template": { "id": "tmpl_456" }, "from": "Welcome <hello@example.com>", "subject": "Getting started" }, "next": null } ] }
Example: Re-engagement with wait_for_event
{ "steps": [ { "key": "trigger", "type": "trigger", "config": { "eventName": "user.created" }, "next": "send_email_1" }, { "key": "send_email_1", "type": "send_email", "config": { "template": { "id": "tmpl_789" }, "from": "Team <team@example.com>", "subject": "Welcome" }, "next": "wait_event_1" }, { "key": "wait_event_1", "type": "wait_for_event", "config": { "eventName": "resend:email.opened", "timeout": "3 days" }, "branches": { "event_received": null, "timeout": "send_email_2" } }, { "key": "send_email_2", "type": "send_email", "config": { "template": { "id": "tmpl_abc" }, "from": "Team <team@example.com>", "subject": "Did you miss this?" }, "next": null } ] }
Example: Condition branch
{ "steps": [ { "key": "trigger", "type": "trigger", "config": { "eventName": "trial.ended" }, "next": "condition_1" }, { "key": "condition_1", "type": "condition", "config": { "type": "rule", "field": "event.converted", "operator": "eq", "value": true }, "branches": { "condition_met": "send_email_1", "condition_not_met": "send_email_2" } }, { "key": "send_email_1", "type": "send_email", "config": { "template": { "id": "tmpl_thanks" }, "from": "Team <team@example.com>", "subject": "Thanks for upgrading!" }, "next": null }, { "key": "send_email_2", "type": "send_email", "config": { "template": { "id": "tmpl_win_back" }, "from": "Team <team@example.com>", "subject": "We'd love to have you back" }, "next": null } ] }
create-broadcastPurpose: Create a broadcast campaign (one email sent to an entire segment). Defines subject, body, and segment; does NOT send yet. Use send-broadcast to send it.
NOT for: Sending a one-off email to specific people (use send-email). Not for adding contacts (use create-contact).
Returns: Broadcast ID. Use this ID with send-broadcast to send, or get-broadcast/update-broadcast to manage.
When to use:
"All contacts" note: Broadcasts require a segment. There is no "all contacts" option in the API. If the user wants to send to all contacts, check list-segments for an existing segment that covers everyone. If none exists, suggest creating one with create-segment.
Workflow: list-segments (if needed) → create-broadcast → get-tiptap-json-content (with include_schema: true) → compose-broadcast → send-broadcast.
Content options after creating:
create-contactCreate a new contact in Resend. Optionally assign to segments and configure topic subscriptions.
create-contact-importBulk-import contacts from a CSV file into Resend. The import is processed asynchronously: this returns an import ID immediately, then use get-contact-import to poll its status and counts. Provide the CSV via exactly one of filePath, content, or url. Max file size 100MB.
create-contact-propertyCreate a new contact property in Resend. A contact property is a custom attribute (e.g. "company_name", "plan_tier") that can be attached to contacts.
create-domainCreate a new domain in Resend. Returns DNS records that must be configured with your DNS provider for verification. You MUST display the DNS records to the user so they can set them up.
create-domain-claimStart a claim for a domain another Resend account has already verified. The domain is recreated under your account with brand-new DKIM keys, so the previous account's DNS records cannot be reused. Returns a TXT record that MUST be added to your DNS to prove ownership. You MUST display the TXT record to the user. After they add it, use verify-domain-claim, then poll get-domain-claim until status is "completed".
create-segmentCreate a new segment in Resend. A segment is a group of contacts that can be used to target specific broadcasts.
create-templateCreate a new email template in Resend. Templates are created in draft status. Use publish-template to make them available for sending. Variables use triple-brace syntax in HTML: {{{VAR_NAME}}}.
Workflow: create-template → get-tiptap-json-content (with include_schema: true) → compose-template → publish-template.
Content options after creating:
create-topicCreate a new topic in Resend. Topics allow contacts to manage their subscription preferences for different types of emails.
create-webhookCreate a new webhook in Resend. A webhook allows you to receive notifications at a specified URL when certain events occur (e.g. email.sent, email.delivered, email.bounced).
disconnect-from-editorRemove agent presence from the Resend dashboard editor. Call this when done editing.
duplicate-templateDuplicate an existing email template in Resend. Creates a new draft copy of the template with a new ID. Accepts a template ID, alias, or Resend dashboard URL.
get-automationPurpose: Get details of a specific automation (with its workflow) or list all automations.
Modes:
id: Returns full automation details including the workflow definition.id: Lists all automations with optional status filter and pagination.When to use:
get-automation-runsPurpose: List runs for an automation, or get details of a specific run.
Modes:
runId: Returns detailed run info with step-by-step execution status, outputs, and errors.runId: Lists runs for the automation with optional status filter.When to use:
Run statuses: running, completed, failed, cancelled Step statuses: pending, running, completed, failed, skipped, waiting
get-broadcastRetrieve full details of a specific broadcast by ID or Resend dashboard URL (e.g. https://resend.com/broadcasts/<id>), including HTML and plain text content.
get-contactGet a contact by ID or email from Resend.
get-contact-importGet the status and counts of a contact import by ID. Use after create-contact-import to track progress (queued, in_progress, completed, failed).
get-contact-propertyGet a contact property by ID from Resend.
get-domainGet a domain by ID from Resend. Returns full domain details including DNS records needed for verification.
get-domain-claimRetrieve the latest claim for a domain by its placeholder Domain ID (the domain_id from create-domain-claim). Returns claim status and the TXT record needed to prove ownership. Poll until status is "completed".
get-emailRetrieve full details of a specific sent transactional email by ID, including message_id, HTML and plain text content.
get-logPurpose: Get detailed information about a specific API request log, including the full request and response bodies.
Returns: Log details: id, created_at, endpoint, method, response_status, user_agent, request_body, response_body.
When to use:
get-received-emailRetrieve full details of a specific received email by ID, including HTML and plain text content, headers, and raw email download URL.
get-received-email-attachmentRetrieve details of a specific attachment from a received email, including a time-limited download URL.
get-segmentGet a segment by ID from Resend.
get-sent-email-attachmentRetrieve details of a specific attachment from a sent email, including a time-limited download URL.
get-suppressionGet a suppression list entry by ID or email address from Resend. Use this to check whether a specific address is suppressed and why (origin: bounce, complaint, or manual).
get-templateGet an email template by ID, alias, or Resend dashboard URL (e.g. https://resend.com/templates/<id>) from Resend. Returns full template details including HTML content, variables, and publish status.
get-tiptap-json-contentPurpose: Retrieve the existing TipTap JSON content of a broadcast or template, optionally bundled with the TipTap schema reference. Also connects the agent to the editor so the avatar is visible while content is being generated.
When to use:
Returns: The TipTap JSON content object for the resource, and optionally the TipTap schema. Use the content as the base for modifications, then pass the updated JSON to compose-broadcast or compose-template.
Note: This tool automatically connects the agent to the editor. The subsequent compose-broadcast or compose-template call will disconnect when done.
Tip: Set include_schema to true to get both the existing content and the schema in one call.
get-topicGet a topic by ID from Resend.
get-webhookGet a webhook by ID from Resend.
list-api-keysList all API keys from Resend. Returns API key names, IDs, and creation dates. Don't bother telling the user the IDs or creation dates unless they ask for them.
list-broadcastsPurpose: List all broadcast campaigns (newsletters/bulk emails to audiences) with ID, name, audience, status, timestamps.
NOT for: Listing transactional emails (use list-emails). Not for listing segments or contacts (use list-segments, list-contacts).
Returns: For each broadcast: id, name, segment_id, status, created_at, scheduled_at, sent_at.
When to use: User asks "show my broadcasts", "what newsletters did I send?", "list campaigns". Use get-broadcast for full details of one.
list-contact-importsList contact imports from Resend. Optionally filter by status. Use to discover import IDs or review past imports.
list-contact-propertiesList all contact properties from Resend. This tool is useful for getting property IDs and seeing which custom attributes are configured. If you need a contact property ID, you MUST use this tool to get all available properties and then ask the user to select the one they want. Don't bother telling the user the IDs or creation dates unless they ask for them.
list-contact-segmentsList all segments a contact belongs to in Resend (by contact ID or email). Don't bother telling the user the IDs or creation dates unless they ask for them.
list-contact-topicsList all topic subscriptions for a contact in Resend (by contact ID or email). Don't bother telling the user the IDs unless they ask for them.
list-contactsPurpose: List contacts from Resend. Optionally filter by segment. Use to discover contact IDs or emails.
NOT for: Listing segments (use list-segments). Not for listing sent emails (use list-emails) or broadcasts (use list-broadcasts).
Returns: For each contact: id, email, first_name, last_name, unsubscribed, created_at.
When to use: User asks "who's in this list?", "show contacts", "who did I add?" Don't bother telling the user the IDs, unsubscribe statuses, or creation dates unless they ask for them.
list-domainsList all domains from Resend. Returns domain names, statuses, regions, and capabilities. Don't bother telling the user the IDs unless they ask for them.
list-emailsPurpose: List recently sent emails (transactional emails sent via send-email) with metadata: recipient, subject, status, timestamps.
NOT for: Listing broadcast campaigns (use list-broadcasts). Not for composing or sending.
Returns: Paginated list with to, subject, status, created_at, message_id, and ID per email.
When to use:
Workflow: list-emails → get-email( id ) when user needs full body or details.
list-logsPurpose: List API request logs for the account. Use to review recent API activity, debug issues, or audit API usage.
Returns: For each log: id, created_at, endpoint, method, response_status, user_agent. Use pagination (limit, after/before) for large lists.
When to use:
list-oauth-grantsList OAuth grants for the team — the apps authorized to act on the team's behalf. Returns every grant, active and revoked; a grant with a non-null revoked_at is no longer active. Each grant includes the client (app) name, scopes, and creation date. Don't bother telling the user the IDs unless they ask for them.
list-received-email-attachmentsList all attachments from a specific received (inbox) email. Returns attachment metadata including filename, size, content type, and a time-limited download URL. Use for emails listed by list-received-emails.
list-received-emailsPurpose: List emails received (inbox) by your Resend receiving address. Use for "show my inbox", "what emails did I get?", "list incoming mail".
NOT for: Listing emails you sent (use list-emails). Not for listing broadcasts (use list-broadcasts).
Returns: Paginated metadata: from, to, subject, message_id, received time. Use get-received-email with an ID for full content.
list-segmentsPurpose: List all segments in the account. Use to get segment IDs required by create-contact, create-broadcast, list-contacts.
NOT for: Listing contacts inside a segment (use list-contacts with segmentId). Not for listing broadcasts (use list-broadcasts).
Returns: For each segment: name, id, created_at. Use pagination (limit, after/before) for large lists.
When to use: User says "show my segments", "what lists do I have?", or before create-contact/create-broadcast when segmentId is unknown.
list-sent-email-attachmentsList all attachments from a specific sent email (from send-email or list-emails). Returns attachment metadata including filename, size, content type, and a time-limited download URL.
list-suppressionsPurpose: List email addresses on the suppression list. Suppressed addresses never receive emails from the account. Optionally filter by origin: "bounce" (added automatically after a hard bounce), "complaint" (added automatically after a spam complaint), or "manual" (added via the API or dashboard).
NOT for: Checking a single address (use get-suppression). Not for listing contacts (use list-contacts).
Returns: For each suppression: email, id, origin, source_id (when present), created_at. Use pagination (limit, after/before) for large lists.
When to use: User says "show my suppression list", "who is suppressed?", or "why isn't this person receiving emails?" combined with a broad look at suppressed addresses.
list-templatesList all email templates from Resend. Returns template names, statuses, and aliases. Don't bother telling the user the IDs unless they ask for them.
list-topicsList all topics from Resend. This tool is useful for getting topic IDs to use with other tools like send-email.
list-webhooksList all webhooks from Resend. Use to get webhook IDs and see which endpoints and events are configured. Not for listing emails, segments, or broadcasts.
manage-eventsPurpose: Create, list, get, update, or remove event definitions in Resend.
Events define named triggers that your application sends to start automations. Each event can have an optional schema that validates payload data.
Actions:
create: Define a new event with a name and optional schema.list: List all event definitions (paginated).get: Get event details by ID or name.update: Update an event's schema.remove: Delete an event. You MUST confirm with the user before removing.Workflow: manage-events (create) → create-automation → send-event
Schema types: string, number, boolean, date
publish-templatePublish an email template in Resend. Templates must be published before they can be used for sending emails. Re-publishing a previously published template makes the latest changes live. Accepts a template ID, alias, or Resend dashboard URL.
remove-api-keyRemove an API key by ID from Resend. Before using this tool, you MUST double-check with the user that they want to remove this API key. Reference the NAME of the API key when double-checking, and warn the user that removing an API key is irreversible and any services using it will lose access. You may only use this tool if the user explicitly confirms they want to remove the API key after you double-check.
remove-automationRemove an automation by ID or Resend dashboard URL. Before using this tool, you MUST double-check with the user that they want to remove this automation. Reference the NAME of the automation when confirming, and warn the user that removal is irreversible and will stop all future runs. You may only use this tool if the user explicitly confirms.
remove-broadcastRemove a broadcast by ID or Resend dashboard URL. Before using this tool, you MUST double-check with the user that they want to remove this broadcast. Reference the NAME of the broadcast when double-checking, and warn the user that removing a broadcast is irreversible. You may only use this tool if the user explicitly confirms they want to remove the broadcast after you double-check.
remove-contactRemove a contact from Resend (by ID or email). Before using this tool, you MUST double-check with the user that they want to remove this contact. Reference the contact's name (if present) and email address when double-checking, and warn the user that removing a contact is irreversible. You may only use this tool if the user explicitly confirms they want to remove the contact after you double-check.
remove-contact-from-segmentRemove a contact from a segment in Resend (by contact ID or email). Before using this tool, you MUST double-check with the user that they want to remove the contact from the segment.
remove-contact-propertyRemove a contact property by ID from Resend. Before using this tool, you MUST double-check with the user that they want to remove this contact property. Reference the KEY of the property when double-checking, and warn the user that removing a contact property is irreversible and will remove the property from all contacts. You may only use this tool if the user explicitly confirms they want to remove the contact property after you double-check.
remove-domainRemove a domain by ID from Resend. Before using this tool, you MUST double-check with the user that they want to remove this domain. Reference the NAME of the domain when double-checking, and warn the user that removing a domain is irreversible and will stop all email sending/receiving for that domain. You may only use this tool if the user explicitly confirms they want to remove the domain after you double-check.
remove-segmentRemove a segment by ID from Resend. Before using this tool, you MUST double-check with the user that they want to remove this segment. Reference the NAME of the segment when double-checking, and warn the user that removing a segment is irreversible. You may only use this tool if the user explicitly confirms they want to remove the segment after you double-check.
remove-suppressionRemove an entry by ID or email address from the suppression list in Resend, allowing the address to receive emails again. Before using this tool, you MUST double-check with the user that they want to remove this suppression. Reference the EMAIL ADDRESS when double-checking, and warn the user that the address will start receiving emails again — if it was suppressed due to a bounce or complaint, sending to it may hurt deliverability. You may only use this tool if the user explicitly confirms they want to remove the suppression after you double-check.
remove-templateRemove an email template by ID, alias, or Resend dashboard URL from Resend. Before using this tool, you MUST double-check with the user that they want to remove this template. Reference the NAME of the template when double-checking, and warn the user that removing a template is irreversible. You may only use this tool if the user explicitly confirms they want to remove the template after you double-check.
remove-topicRemove a topic by ID from Resend. Before using this tool, you MUST double-check with the user that they want to remove this topic. Reference the NAME of the topic when double-checking, and warn the user that removing a topic is irreversible. You may only use this tool if the user explicitly confirms they want to remove the topic after you double-check.
remove-webhookRemove a webhook by ID from Resend. Before using this tool, you MUST double-check with the user that they want to remove this webhook. Reference the ENDPOINT of the webhook when double-checking, and warn the user that removing a webhook is irreversible. You may only use this tool if the user explicitly confirms they want to remove the webhook after you double-check.
revoke-oauth-grantRevoke an OAuth grant by ID. Before using this tool, you MUST double-check with the user that they want to revoke this grant. Reference the NAME of the app (client) when double-checking, and warn the user that revocation is immediate and irreversible — every access and refresh token issued under the grant stops working, and the app would need to be re-authorized to regain access. You may only use this tool if the user explicitly confirms they want to revoke the grant after you double-check.
send-batch-emailsPurpose: Send up to 100 transactional emails in one API call. Each item has the same fields as send-email (to, subject, text, from, etc.).
NOT for: Sending one email (use send-email) or the same content to a segment (use create-broadcast + send-broadcast).
When to use: User wants to send many individual emails in bulk (e.g. 50 password resets, 100 receipts). Not for one-to-many broadcasts.
send-broadcastPurpose: Send (or schedule) an existing broadcast by ID. The broadcast must have been created with create-broadcast first.
NOT for: Sending a new one-off email (use send-email). Not for creating the broadcast content (use create-broadcast).
Returns: Send confirmation and broadcast ID.
When to use:
Workflow: create-broadcast → send-broadcast. Use list-broadcasts to find existing draft/sent broadcasts.
send-emailPurpose: Send a single transactional email to one or more recipients immediately (or schedule it). Use for one-off messages, notifications, and direct replies.
NOT for: Sending the same email to a whole list/audience (use create-broadcast + send-broadcast). Not for managing contacts or audiences.
Returns: Send confirmation and email ID.
When to use:
Workflow: Get recipient(s) and content from user → send-email. Use list-emails or get-email to check delivery status afterward.
Key trigger phrases: "Send an email", "Email this to", "Notify", "Send a message", "Reply to them", "Schedule an email"
send-eventPurpose: Fire an event to trigger automations for a specific contact.
When to use:
Workflow: create-event (if needed) → create-automation (if needed) → send-event
Important:
update-automationPurpose: Update an automation's name, status, or workflow.
When to use:
Important:
The workflow is a JSON object with one key: "steps" — an array of step objects.
Each step has: key (unique string), type, config, and either "next" (string|null) or "branches" (for branching steps). Use keys like: "trigger", "send_email_1", "delay_1", "condition_1", "wait_event_1".
Step types
trigger — starts the automation when an event fires (required, exactly one)
config: { "eventName": "<event_name>" } Uses "next".
send_email — send an email using a published template
config: { "template": { "id": "<template_id>", "variables": { "<key>": "<value>" } }, "from": "Name <sender@example.com>", "subject": "Email subject", "replyTo": "<address>" } "from" and "subject" are resolved from the step config first, then fall back to the template. If neither provides a "from", the email will silently fail to send. If neither provides a "subject", the run will error. Best practice: always set "from" and "subject" on the step config so the automation is self-contained. Use list-domains to find verified domains for "from". "replyTo" and "variables" are optional. Variables can use { "var": "event.<field>" } or { "var": "contact.<field>" } for dynamic values. Uses "next".
delay — pause the workflow
config: { "duration": "<human-readable>" } Examples: "30 minutes", "1 hour", "2 days", "1 week". Max 30 days. Uses "next".
condition — conditional split based on contact or event data
config: A condition rule object: Single rule: { "type": "rule", "field": "event.<field>" or "contact.<field>", "operator": "<op>", "value": <value> } Compound: { "type": "and"|"or", "rules": [<rule>, ...] } Operators: eq, neq, gt, gte, lt, lte, contains, starts_with, ends_with, exists, is_empty. exists/is_empty do not require a value. Uses "branches": { "condition_met": "<step_key>", "condition_not_met": "<step_key_or_null>" }
wait_for_event — pause until a specific event arrives or timeout
config: { "eventName": "<event_name>", "timeout": "<human-readable>", "filterRule": <optional condition rule> } For email lifecycle events use "resend:email.<opened|clicked|bounced|delivered|complained|failed|suppressed>". Uses "branches": { "event_received": "<step_key>", "timeout": "<step_key_or_null>" }
contact_update — update contact fields
config: { "firstName": "<value>", "lastName": "<value>", "unsubscribed": true|false, "properties": { "<key>": "<value>" } } All fields optional. Values can use { "var": "event.<field>" } for dynamic data. Uses "next".
contact_delete — remove the contact from the audience
config: {} Uses "next".
add_to_segment — add contact to a segment
config: { "segmentId": "<segment_id>" } Uses "next".
Rules
Example: Linear drip campaign
{ "steps": [ { "key": "trigger", "type": "trigger", "config": { "eventName": "user.created" }, "next": "send_email_1" }, { "key": "send_email_1", "type": "send_email", "config": { "template": { "id": "tmpl_123" }, "from": "Welcome <hello@example.com>", "subject": "Welcome!" }, "next": "delay_1" }, { "key": "delay_1", "type": "delay", "config": { "duration": "3 days" }, "next": "send_email_2" }, { "key": "send_email_2", "type": "send_email", "config": { "template": { "id": "tmpl_456" }, "from": "Welcome <hello@example.com>", "subject": "Getting started" }, "next": null } ] }
Example: Re-engagement with wait_for_event
{ "steps": [ { "key": "trigger", "type": "trigger", "config": { "eventName": "user.created" }, "next": "send_email_1" }, { "key": "send_email_1", "type": "send_email", "config": { "template": { "id": "tmpl_789" }, "from": "Team <team@example.com>", "subject": "Welcome" }, "next": "wait_event_1" }, { "key": "wait_event_1", "type": "wait_for_event", "config": { "eventName": "resend:email.opened", "timeout": "3 days" }, "branches": { "event_received": null, "timeout": "send_email_2" } }, { "key": "send_email_2", "type": "send_email", "config": { "template": { "id": "tmpl_abc" }, "from": "Team <team@example.com>", "subject": "Did you miss this?" }, "next": null } ] }
Example: Condition branch
{ "steps": [ { "key": "trigger", "type": "trigger", "config": { "eventName": "trial.ended" }, "next": "condition_1" }, { "key": "condition_1", "type": "condition", "config": { "type": "rule", "field": "event.converted", "operator": "eq", "value": true }, "branches": { "condition_met": "send_email_1", "condition_not_met": "send_email_2" } }, { "key": "send_email_1", "type": "send_email", "config": { "template": { "id": "tmpl_thanks" }, "from": "Team <team@example.com>", "subject": "Thanks for upgrading!" }, "next": null }, { "key": "send_email_2", "type": "send_email", "config": { "template": { "id": "tmpl_win_back" }, "from": "Team <team@example.com>", "subject": "We'd love to have you back" }, "next": null } ] }
update-broadcastUpdate broadcast metadata by ID or Resend dashboard URL (name, subject, from, html, text, segment, preview text, reply-to). To edit TipTap content, use compose-broadcast instead.
Important: The API requires from and segmentId to be set on the broadcast. If the broadcast was created from the dashboard, these may be empty. Always call get-broadcast first to check, and include from and segmentId in your update if they are not already set. Use list-domains to find verified domains for the from address, and list-segments to find segment IDs.
Note on html/text fields: Setting html or text via this tool replaces any content previously set via compose-broadcast. This switch is lossy — some content or formatting may be lost. Prefer compose-broadcast for content changes. If the broadcast was composed with TipTap content, ask the user before overwriting it with raw HTML.
update-contactUpdate a contact in Resend (by ID or email).
update-contact-propertyUpdate an existing contact property in Resend. Only the fallback value can be changed — the key and type cannot be modified after creation.
update-contact-topicsUpdate topic subscriptions for a contact in Resend (by contact ID or email).
update-domainUpdate an existing domain in Resend. Allows changing tracking settings, TLS mode, and capabilities.
update-emailReschedule a scheduled email by updating its scheduled send time. Only works for emails that were scheduled and have not yet been sent.
update-templateUpdate template metadata by ID, alias, or Resend dashboard URL (name, subject, from, html, variables, etc.). After updating a published template, use publish-template again to make the changes live. To edit TipTap content, use compose-template instead.
Note on html/text fields: Setting html or text via this tool replaces any content previously set via compose-template. This switch is lossy — some content or formatting may be lost. Prefer compose-template for content changes. If the template was composed with TipTap content, ask the user before overwriting it with raw HTML.
update-topicUpdate an existing topic in Resend. Note: defaultSubscription cannot be modified after creation.
update-webhookUpdate an existing webhook in Resend. You can change the endpoint URL, subscribed events, or enable/disable the webhook.
verify-domainTrigger domain verification in Resend. This starts an asynchronous verification process that checks if the DNS records are correctly configured. The domain status will temporarily show as "pending" during verification.
verify-domain-claimTrigger asynchronous DNS verification and ownership transfer for a domain claim, using the placeholder Domain ID. The claim stays "pending" while verification runs; poll get-domain-claim for status. Once "completed", the transferred domain has NEW DKIM records — fetch them with get-domain, add them to DNS, then run verify-domain.
BEFORE YOU INSTALL
91 tools when we connected. Tool names are kebab-case, such as send-email. A restricted Resend API key leaves all 91 listed but makes some fail when called.
CONTEXT COST
Rated by the size of the 91 tool definitions that ride along on every turn, not by how many there are
INSTALLATION
npx add-mcp resend-mcp --name resend --env "RESEND_API_KEY=<YOUR_RESEND_API_KEY>"https://mcp.resend.com/mcpAdd this hosted endpoint to your MCP client using the credentials listed under Requirements.
claude mcp add --transport http resend https://mcp.resend.com/mcpSettings > Connectors > Add custom connector > https://mcp.resend.com/mcp
{
"mcpServers": {
"resend": {
"url": "https://mcp.resend.com/mcp"
}
}
}codex mcp add resend --url https://mcp.resend.com/mcp{
"servers": {
"resend": {
"type": "http",
"url": "https://mcp.resend.com/mcp"
}
}
}{
"mcpServers": {
"resend": {
"serverUrl": "https://mcp.resend.com/mcp"
}
}
}{
"mcpServers": {
"resend": {
"url": "https://mcp.resend.com/mcp",
"headers": {
"Authorization": "Bearer <YOUR_RESEND_API_KEY>"
}
}
}
}claude mcp add resend -e RESEND_API_KEY=<YOUR_RESEND_API_KEY> -- npx -y resend-mcpcodex mcp add resend \
--env RESEND_API_KEY=<YOUR_RESEND_API_KEY> \
-- npx -y resend-mcp{
"mcpServers": {
"resend": {
"command": "npx",
"args": [
"-y",
"resend-mcp"
],
"env": {
"RESEND_API_KEY": "<YOUR_RESEND_API_KEY>"
}
}
}
}{
"servers": {
"resend": {
"command": "npx",
"args": [
"-y",
"resend-mcp"
],
"env": {
"RESEND_API_KEY": "<YOUR_RESEND_API_KEY>"
}
}
}
}{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"resend": {
"type": "local",
"command": [
"npx",
"-y",
"resend-mcp"
],
"enabled": true,
"environment": {
"RESEND_API_KEY": "<YOUR_RESEND_API_KEY>"
}
}
}
}{
"mcpServers": {
"resend": {
"command": "npx",
"args": [
"-y",
"resend-mcp"
],
"env": {
"RESEND_API_KEY": "<YOUR_RESEND_API_KEY>",
"SENDER_EMAIL_ADDRESS": "onboarding@resend.dev"
}
}
}
}{
"mcpServers": {
"resend": {
"url": "http://127.0.0.1:3000/mcp",
"headers": {
"Authorization": "Bearer <YOUR_RESEND_API_KEY>"
}
}
}
}