If your agent sends email through a transactional provider like SendGrid, Resend, or Postmark, you have outbound covered. What you don’t have is a receive path. When someone replies to the agent’s email, that reply either bounces, goes to a shared no-reply address no one checks, or lands in a human’s inbox that the agent can’t access programmatically.
Nylas Agent Accounts give the agent a full mailbox — send and receive, with threading, webhooks, and folder management built in. This guide walks through the migration.
What changes and what doesn’t
Section titled “What changes and what doesn’t”| Concern | Transactional provider | Agent Account |
|---|---|---|
| Outbound | API call to send | Same — API call to send (POST /messages/send) |
| Inbound | No receive path (or manual polling of a shared inbox) | Built-in mailbox. Replies land automatically, fire message.created webhook |
| Threading | You manage Message-ID tracking yourself | Nylas preserves headers and groups messages into threads automatically |
| Reply detection | Parse forwarded email or poll a separate inbox | Webhook fires within seconds of a reply arriving |
| Domain / DNS | SPF, DKIM, DMARC records for the transactional provider | MX, SPF, DKIM, DMARC records for Nylas (or use a *.nylas.email trial domain) |
| Deliverability | Provider handles warm-up, reputation | Nylas handles outbound pipeline; you manage your domain’s reputation |
| State | External — you build everything | Threads API gives you conversation history; state mapping is still yours |
The core change is: instead of the agent talking into a void and hoping someone reads the output, replies flow back through the same channel and the agent can act on them.
Step 1: Provision the Agent Account
Section titled “Step 1: Provision the Agent Account”From the Nylas CLI:
Or through the API:
curl --request POST \ --url "https://api.us.nylas.com/v3/connect/custom" \ --header "Authorization: Bearer <NYLAS_API_KEY>" \ --header "Content-Type: application/json" \ --data '{ "provider": "nylas", "settings": { "email": "[email protected]" } }'Save the grant_id from the response. This is the Agent Account’s identity for every subsequent API call.
If you’re using a custom domain, you’ll need MX and TXT records pointed at Nylas before the account can receive mail. See Provisioning and domains for the DNS setup. For prototyping, a *.nylas.email trial subdomain works out of the box.
Step 2: Replace the send call
Section titled “Step 2: Replace the send call”The API shape is similar to what you already have. Here’s the before and after.
Before (transactional provider):
// SendGrid / Resend / Postmark -- outbound onlyawait sendgrid.send({ subject: "Following up on your demo request", html: "<p>Hi Alice -- wanted to follow up on...</p>",});// That's it. If Alice replies, the agent never sees it.After (Nylas Agent Account):
const sent = await nylas.messages.send({ identifier: AGENT_GRANT_ID, requestBody: { subject: "Following up on your demo request", body: "<p>Hi Alice -- wanted to follow up on...</p>", },});
// Store the thread_id so you can match replies later.await db.conversations.create({ threadId: sent.data.threadId, step: "awaiting_reply",});The key difference: after sending, you store the thread_id. When Alice replies, you’ll match it back.
Step 3: Subscribe to inbound
Section titled “Step 3: Subscribe to inbound”From the Nylas CLI:
nylas webhook create \ --url https://youragent.example.com/webhooks/nylas \ --triggers message.createdOr through the API:
curl --request POST \ --url "https://api.us.nylas.com/v3/webhooks" \ --header "Authorization: Bearer <NYLAS_API_KEY>" \ --header "Content-Type: application/json" \ --data '{ "trigger_types": ["message.created"], "webhook_url": "https://youragent.example.com/webhooks/nylas" }'This is the receive path you didn’t have before. Nylas fires message.created within seconds of a reply arriving.
Step 4: Handle replies
Section titled “Step 4: Handle replies”When Alice replies, the webhook fires. Look up the thread and restore context.
app.post("/webhooks/nylas", async (req, res) => { res.status(200).end();
const event = req.body; if (event.type !== "message.created") return;
const msg = event.data.object; if (msg.grant_id !== AGENT_GRANT_ID) return;
// Skip the agent's own outbound messages.
// Look up the conversation. const conversation = await db.conversations.findByThreadId(msg.thread_id); if (!conversation) { // New inbound -- not a reply to something we sent. return; }
// Fetch the full body. const full = await nylas.messages.find({ identifier: AGENT_GRANT_ID, messageId: msg.id, });
// The agent now has: // - The reply body (full.data.body) // - The conversation context (conversation.step, conversation.metadata) // - The full thread via Nylas Threads API if needed // Hand it to the LLM or workflow engine. await processReply(full.data, conversation);});This is the loop that didn’t exist with a transactional provider. The agent sends, the recipient replies, and the agent sees the reply — all on the same address, in the same thread.
Step 5: Reply in-thread
Section titled “Step 5: Reply in-thread”When the agent responds, pass reply_to_message_id so the conversation threads correctly.
await nylas.messages.send({ identifier: AGENT_GRANT_ID, requestBody: { replyToMessageId: inboundMessage.id, to: inboundMessage.from, subject: `Re: ${inboundMessage.subject}`, body: agentResponse, },});The recipient sees a normal threaded reply. No “sent via” branding, no relay footer.
DNS considerations
Section titled “DNS considerations”If you’re moving from a transactional provider to a Nylas Agent Account on the same domain, you’ll need to update your MX records to point at Nylas instead of the transactional provider. This is only relevant if you want inbound mail on the domain to route to Nylas.
A common pattern is to use a subdomain:
- Keep
yourcompany.comMX records as-is (pointed at Google Workspace, Microsoft 365, or wherever your team’s email lives). - Register
agents.yourcompany.comwith Nylas and point its MX records at Nylas. - The agent sends from
[email protected]and receives replies there.
This isolates the agent’s domain reputation from your primary domain, which matters at volume.
Keep in mind
Section titled “Keep in mind”- You don’t have to replace the transactional provider entirely. If you’re happy with your outbound setup for receipts, password resets, or marketing, keep it. Use an Agent Account specifically for the conversations where the agent needs to see replies. Different addresses, different use cases.
- Warm up the domain. A new domain sending hundreds of emails on day one will get flagged. Start with low volume and ramp up over a week or two. See Domain warm up.
- The 100-message-per-day default is real. Agent Accounts have a soft send cap. If your agent sends at volume, request a higher limit through your plan or provision multiple Agent Accounts across multiple domains.
- Threading is automatic. You don’t need to generate
Message-IDvalues or setIn-Reply-Toheaders yourself. Nylas handles all of it. Just passreply_to_message_idwhen you want to reply in-thread.
What’s next
Section titled “What’s next”- Handle email replies in an agent loop — the detailed reply detection and routing recipe
- Build a multi-turn email conversation — the full send-receive-respond loop with state management
- Email threading for agents — how threading headers work and how Nylas preserves them
- Provisioning and domains — DNS setup and multi-domain patterns
- Give your agent its own email — the getting-started guide for Agent Account email