AI 资讯
Restricting Attachments in Agent Inboxes
Three fields on a policy decide which attachments ever reach your email agent: { "name" : "Locked-down agent inbox" , "limits" : { "limit_attachment_size_limit" : 26214400 , "limit_attachment_count_limit" : 20 , "limit_attachment_allowed_types" : [ "application/pdf" , "image/png" ] } } Size (that's 25 MB in bytes), count per message, and an allowlist of MIME types. POST that to /v3/policies , attach the resulting policy_id to a workspace, and every Agent Account in the workspace enforces it on inbound mail from then on. Why an autonomous reader needs this more than you do When a human gets a suspicious attachment, there's a judgment step: weird sender, weird filename, don't open it. An email agent has no such instinct unless you build one — and the agents most worth building are exactly the ones that process attachments: parsing invoices, extracting resumes, reading shipped documents. That processing step is the attack surface. A hostile PDF aimed at your parser, a 10,000-page document aimed at your token budget, a zip bomb aimed at your storage — all of them arrive the same way legitimate input does. You can defend in application code, but then every consumer of the mailbox has to get it right, forever. Policy limits on Nylas Agent Accounts (a beta feature) enforce the constraint at the mailbox itself, before any of your code runs. One clarification that saves a support ticket: inbound rules can't do this job. Rules match on sender fields — from.address , from.domain , from.tld — and know nothing about what a message carries. Attachment control lives on the policy, and only there. From policy to enforced, end to end The policy applies through a workspace, not directly to a grant. The full wiring is three calls. Create the policy at /v3/policies , set it as the workspace's policy_id (a PATCH /v3/workspaces/{workspace_id} if the workspace already exists), then create the account into that workspace: curl --request POST \ --url "https://api.us.nylas.com/v3/connect/cus
AI 资讯
Track Email Opens From Your Agent's Outreach
You built an outreach agent, it sent 80 follow-ups this week, and you have no idea what happened to any of them. Did the prospect open the message? Click the demo link? Is the silence a "no" or a spam-folder problem? Without engagement signals, your agent is firing into the void and your follow-up logic is guesswork. The fix has two parts: turn tracking on when you send, and subscribe to the webhooks that report what recipients do. Tracking starts at send time, not after Opens, clicks, and replies are only reported for messages sent with tracking enabled — you can't retroactively track a message that's already out. On the Send Message request, pass a tracking_options object with three booleans plus an optional label that gets echoed back in every notification: curl --request POST \ --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/messages/send' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer <NYLAS_API_KEY>' \ --data-raw '{ "subject": "Quick follow-up on your trial", "body": "Thanks for trying us out. Reply or <a href=\"https://example.com/demo\">book a demo</a> when ready.", "to": [{ "name": "Kim Townsend", "email": "kim@example.com" }], "tracking_options": { "opens": true, "links": true, "thread_replies": true, "label": "trial-followup-q2" } }' The label is the piece agents should lean on: stamp it with your campaign ID or contact ID and every later notification carries it, so your handler matches events back to outreach state without storing a message-ID mapping. One caveat before you test: message tracking needs a production application — trial accounts get "Tracking options are not allowed for trial accounts" back. Three triggers, one endpoint Engagement events arrive over webhooks. Subscribe one HTTPS endpoint to all three triggers — message.opened , message.link_clicked , and thread.replied : curl --request POST \ --url 'https://api.us.nylas.com/v3/webhooks/' \ --header 'Content-Type: application/json' \ --header 'Autho
AI 资讯
Agent-to-Agent Communication Over Email
Your procurement agent needs three quotes for a hardware order. The vendor on the other side runs a sales agent that answers pricing questions automatically. Neither team has talked to the other. There's no shared API contract, no agreed-upon protocol, no integration project. The procurement agent just... sends an email. The sales agent replies. A negotiation happens. That works because both agents have something most AI agents don't: a real email address. The interop problem nobody's protocol has solved The industry is busy designing agent-to-agent protocols — schemas for capability discovery, message envelopes, trust handshakes. All of them share a bootstrapping problem: both sides have to adopt the same spec, and specs only help once everyone you want to talk to has implemented them. Email skipped that problem decades ago. It's federated (anyone can run a mailbox on any domain), it has identity built in (the address), it has conversation state built in (threading), and every organization on earth already accepts inbound delivery. An agent that speaks SMTP can communicate with any counterpart — human or machine — without anyone agreeing on anything in advance. What each agent needs: a first-class identity Agent Accounts — a beta feature from Nylas — give an agent exactly that. Each one is a hosted mailbox like procurement-agent@yourcompany.com that sends, receives, maintains folders, and is indistinguishable from a human-operated account to anyone interacting with it over SMTP. Under the hood it's just another grant: you get a grant_id that works with the existing Messages, Drafts, Threads, Folders, Attachments, and Webhooks endpoints. The "indistinguishable from a human account" part matters more than it sounds. It means agent-to-agent and agent-to-human are the same code path. Your procurement agent doesn't care whether sales@vendor.example is a person, a bot, or a person who hands hard questions to a bot. The conversation degrades gracefully to human handling a
AI 资讯
Human-in-the-Loop: Email Approval Workflows for Agents
The most effective safety control for an email agent isn't a better model, a longer system prompt, or a stricter eval suite. It's a draft folder. Here's the setup. Nylas Agent Accounts — currently in beta — are hosted mailboxes your application creates and controls entirely through the API. Each one is a real address with a grant_id that works against the existing Messages, Drafts, Threads, and Folders endpoints, and each mailbox ships with six system folders: inbox , sent , drafts , trash , junk , and archive . That drafts folder is where your approval workflow lives. Full autonomy is a choice, not a default A common pattern for support mailboxes: an LLM drafts replies to common questions, and humans approve the sensitive ones via a webhook flow. The agent handles the boring 80% on its own — password reset instructions, shipping status, "where's the invoice" — and anything touching refunds, legal language, or an angry customer goes through a person first. The threat you're mitigating is mundane: a model that's confidently wrong. Hallucinated discounts, replies to the wrong thread, a tone-deaf response to a complaint. None of these are exotic attacks. They're the everyday failure modes of putting a probabilistic system on an outbound channel, and the mitigation is to put a deterministic gate between "the model wrote something" and "a customer received it." The gate is three API calls The flow: a message.created webhook fires when mail arrives, your classifier decides the risk level, and high-risk replies become drafts instead of sends. Drafts support full CRUD at /v3/grants/{grant_id}/drafts , so the agent creates one like this: curl --request POST \ --url "https://api.us.nylas.com/v3/grants/ $GRANT_ID /drafts" \ --header "Authorization: Bearer $NYLAS_API_KEY " \ --header "Content-Type: application/json" \ --data '{ "subject": "Re: Refund request for order 4821", "body": "Hi Sam, I have processed the refund...", "to": [{ "email": "sam@example.com" }], "reply_to_mess
AI 资讯
Migrating From Transactional Email to Agent Accounts
This is what most agent email code looks like today: // SendGrid / Resend / Postmark — outbound only await sendgrid . send ({ to : " prospect@example.com " , from : " outreach@yourcompany.com " , 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. The send works fine. The problem is everything after: when Alice replies, that reply bounces, lands at a no-reply nobody reads, or hits a human inbox the agent can't reach programmatically. The agent is talking into a void. Transactional providers were built for receipts and password resets — one-way mail — and an agent that's supposed to hold a conversation needs a receive path those APIs simply don't have. Agent Accounts (a beta feature from Nylas) close that gap with a full hosted mailbox: send and receive, with threading, webhooks, and folders built in. Here's what the migration actually involves. The delta, honestly Outbound barely changes — it's still an API call. The new parts are everything transactional providers never gave you: Concern Transactional provider Agent Account Outbound API call Same — POST /messages/send Inbound None (or polling a shared inbox) Replies land automatically, fire message.created Threading You track Message-ID yourself Headers preserved, threads grouped automatically Reply detection Parse forwards, poll Webhook within seconds of arrival DNS SPF/DKIM/DMARC for the provider MX, SPF, DKIM, DMARC for the mailbox host Provision the mailbox One call creates the account; the response includes a grant_id that identifies it on every later request: 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": "outreach@agents.yourcompany.com" } }' (Or nylas agent account create outreach@agents.yourcompany.com from the CLI.) C
AI 资讯
Handling Email Replies in an Agent Loop
You built the outbound half of an email agent. It sends a well-crafted message, the recipient writes back six hours later... and your agent has no idea. The reply either gets ignored or — arguably worse — gets treated as a brand-new conversation, and the agent reintroduces itself to someone it emailed yesterday. That gap between "can send" and "can converse" is where most email agents stall. Closing it takes four pieces: detection, context, routing, and a threaded response. Here's each one, using a Nylas Agent Account (in beta) as the mailbox — a hosted address the agent owns outright. Step 1: know a reply when you see one Every message.created webhook payload carries a thread_id . If the agent sent the original message, that thread already exists in your state store. So detection is a lookup, not a parsing exercise: app . post ( " /webhooks/nylas " , async ( req , res ) => { // Verify X-Nylas-Signature here. 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 ; const context = await db . getThreadContext ( msg . thread_id ); if ( context ) { await handleReply ( msg , context ); // active conversation } else { await handleNewMessage ( msg ); // fresh inbound — triage it } }); Why does this work without touching a single header? Because the threading already happened upstream: messages get grouped by their In-Reply-To and References headers, which every mail client sets on a reply. You never parse them yourself — the Threads API did the work. Step 2: pull the full conversation The webhook payload is a summary — subject , from , snippet . Before an LLM decides how to answer "sounds good, let's do Thursday," it needs to know what was proposed. Fetch the full message body and the thread: const fullMessage = await nylas . messages . find ({ identifier : AGENT_GRANT_ID , messageId : msg . id , }); const thread = await nylas . thread
AI 资讯
Stop Your Agent From Replying Twice: Dedup Patterns
Ever watched an email agent reply to the same message twice? The recipient gets two near-identical responses seconds apart, screenshots them, and your carefully engineered assistant suddenly looks like a script with a stutter. Worse: under real load, this isn't a freak event. It's the default outcome if you haven't designed against it. The double-reply problem has three distinct causes, and each one needs its own fix. Let's walk through them. Why duplicates happen at all First cause: webhook redelivery . Nylas — like most webhook providers — guarantees at-least-once delivery. If your endpoint doesn't return a 200 fast enough, or a transient network blip eats the response, the same message.created notification shows up again. Process both, send two replies. Second: concurrent workers . Your handler probably runs on multiple instances — Lambda invocations, ECS tasks, worker processes. Two of them can pick up the same notification at nearly the same instant and both start generating a reply. Third: shared inboxes . Two agents (or an agent and a human) watching the same mailbox can both decide a message is theirs to answer. This one isn't a duplicate event at all — it's a coordination problem, and it's the hardest to patch at the application layer. Fix one: deduplicate deliveries Track which message IDs you've processed, and check before doing anything else: app . post ( " /webhooks/nylas " , async ( req , res ) => { res . status ( 200 ). end (); const event = req . body ; if ( event . type !== " message.created " ) return ; const messageId = event . data . object . id ; // Atomic check-and-set. If the key exists, bail. const alreadyProcessed = await db . processedMessages . setIfAbsent ( messageId , { receivedAt : Date . now (), }); if ( alreadyProcessed ) return ; await handleMessage ( event . data . object ); }); The check-and-set must be atomic. In Redis that's SET messageId 1 NX EX 86400 ; in Postgres it's INSERT ... ON CONFLICT DO NOTHING with a row-count check. G
AI 资讯
Multi-Turn Email Conversations for LLM Agents
Day 0, 10:00 — your agent sends a demo follow-up. Day 2, 14:37 — the prospect replies with a question. Day 2, 14:39 — they send a second thought. Day 5 — silence, then a reply to something the agent said a week ago. Somewhere between day 0 and day 5, your process restarted twice and deployed once. A single send-and-forget email is easy. The timeline above is the actual job: a conversation spanning five exchanges over days, where the agent has to remember what it said, what it's waiting for, and where in the workflow it stands — across restarts, deploys, and hours of dead air. The multi-turn conversation recipe builds this loop on a Nylas Agent Account (the feature's in beta), running entirely on webhooks and the Threads API — no polling, no missed messages. State lives outside the model The core design decision: every active conversation gets a durable record keyed by the thread ID. const conversationRecord = { threadId : " nylas-thread-id " , grantId : AGENT_GRANT_ID , contactEmail : " prospect@example.com " , purpose : " demo_followup " , // What started this conversation step : " awaiting_reply " , // Where in the workflow we are turnCount : 1 , maxTurns : 10 , // Safety cap before escalation lastActivityAt : " 2026-04-14T10:00:00Z " , metadata : {}, }; The step field is the heart of it — a tiny state machine tracking what the agent is waiting for, which determines how the next inbound message gets handled. The store has to be durable (Postgres, Redis with AOF, DynamoDB); the gap between messages can be days, so in-memory state is a non-starter. Starting a conversation means sending the first message and persisting the record under the threadId the send returns: async function startConversation ({ to , subject , body , purpose , metadata }) { const sent = await nylas . messages . send ({ identifier : AGENT_GRANT_ID , requestBody : { to : [{ email : to . email , name : to . name }], subject , body , }, }); await db . conversations . create ({ threadId : sent . dat
AI 资讯
One Agent Identity Per Customer: Multi-Tenant Email
Provisioning a tenant-scoped email identity for your SaaS is one POST: 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", "workspace_id": "<WORKSPACE_ID>", "settings": { "email": "scheduling@customer-a.com" } }' No OAuth dance, no refresh token — just an address on a registered domain. The response comes back already valid: { "request_id" : "5967ca40-a2d8-4ee0-a0e0-6f18ace39a90" , "data" : { "id" : "b1c2d3e4-5678-4abc-9def-0123456789ab" , "provider" : "nylas" , "grant_status" : "valid" , "email" : "scheduling@customer-a.com" , "scope" : [], "created_at" : 1742932766 } } The data.id is a grant_id that works with every existing Nylas endpoint, and the account is live immediately. That's the primitive behind a multi-tenant pattern worth knowing: one Agent Account per customer, on each customer's own verified domain, all managed from a single application. (Agent Accounts are in beta, so the surface may shift before GA.) The architecture in one paragraph Your app runs scheduling@customer-a.com , scheduling@customer-b.com , and so on — same code path, different identities. Each account has its own policy, its own send quota, and its own sender reputation. A single application can manage accounts across an unlimited number of registered domains, so tenant count is a billing question, not an architectural one. Customer A's deliverability problems stay Customer A's; nothing they do contaminates Customer B's mail. Domains: register once, mint accounts forever The provisioning docs lay out two domain strategies you can mix freely in one application: Strategy Address format Setup Trial domain alias@<your-application>.nylas.email None — instant Your own domain alias@yourdomain.com MX + TXT records at the DNS provider For the per-customer pattern, each tenant brings their domain. You register it once per organization (picking the US
AI 资讯
Voice Agents That Follow Up by Email
Last sprint, a team I talked to demoed a voice agent that handled support calls impressively — right up until a caller asked "can you email me those instructions?" and the room went quiet. The agent could talk about the docs. It had no address to send them from. The workaround on the whiteboard afterwards was grim: relay through a shared noreply@ , lose the replies, reconcile threads manually in the ticketing system. Voice agents hit this wall constantly, because phone calls generate follow-up artifacts — reset instructions, documents, meeting recaps — and email is how callers expect to receive them. The clean fix is the same one that works for text agents: the voice agent gets its own mailbox. The identity half A Nylas Agent Account is a hosted mailbox you create through the API — Agent Accounts are in beta — and the voice use case from the product docs is exactly the scenario above: a voice agent taking support calls sends documents, reset instructions, or meeting recaps from its own voice-agent@yourcompany.com address the moment the caller asks. The part that makes it more than a send pipe: when the caller replies, the reply returns through the same account, so the full conversation is one thread in one mailbox. The phone call and its written follow-ups stop living in separate systems. Each account is a real grant with a grant_id that works against the existing Messages, Threads, and Webhooks endpoints, ships with six system folders, and sends up to 200 messages per account per day on the free plan. The plumbing half The voice agents recipe covers how the runtime actually calls email tools. The flow is the same regardless of vendor: speech → STT → LLM (function-calling) → subprocess(nylas …) → JSON → LLM → TTS → speech The LLM decides on a tool, the runtime spawns a Nylas CLI subprocess with --json , the result comes back, and the model composes a spoken response. On LiveKit, a tool is just a decorated function: from livekit.agents import function_tool import sub
AI 资讯
How an AI Agent Can Sign Up for a Service on Its Own
An AI agent that can't receive email can't finish a signup form. That one limitation quietly rules out a huge class of autonomous workflows — the research agent that needs a developer account on a data source, the QA agent that registers for a SaaS on every test run, the purchasing agent that needs a buyer profile on a marketplace. Every one of them dies at "we've sent you a verification email." The blocker was never the form. Headless browsers fill forms fine. The blocker is that verification emails traditionally route to a human inbox, which puts a human back in a loop that was supposed to have none. Agent Accounts remove that dependency. The agent gets its own hosted mailbox (the feature is in beta), signs up with that address, catches the verification email via webhook, and completes onboarding by itself. Here's the whole flow, condensed from the cookbook recipe. Provision, subscribe, sign up Three setup moves. First, create the mailbox — one CLI command, or POST /v3/connect/custom with "provider": "nylas" if you'd rather hit the API: nylas agent account create signup-agent@agents.yourdomain.com The API version is the same Bring Your Own Authentication endpoint other providers use — no OAuth refresh token involved: 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": "signup-agent@agents.yourdomain.com" } }' Save the grant ID it prints. Second, subscribe to inbound mail: nylas webhook create \ --url https://youragent.example.com/webhooks/signup \ --triggers message.created The message.created event fires within a second or two of mail arriving, carrying the message's summary fields. The webhook URL has to be publicly reachable over HTTPS; for local development, the recipe recommends VS Code port forwarding or Hookdeck to expose your dev server. Third, submit the target service's signup form wit
AI 资讯
Extract OTP Codes From Email, Automatically
What does your automation do when the login flow it's driving sends a six-digit code instead of a confirmation link? For most teams the honest answer is "a human goes and checks a shared inbox," which is a strange bottleneck to leave in the middle of an otherwise fully automated pipeline. There's a cleaner shape: the agent owns the mailbox the code lands in. With a Nylas Agent Account — a hosted mailbox controlled entirely through the API, currently in beta — the OTP email arrives, a webhook fires, your handler extracts the code, and whatever orchestrates the login gets it back. No human, no inbox-checking Slack message, no screen-scraping Gmail. Step one: make sure it's the right email A message.created webhook fires on every inbound message, so the first job is filtering down to the one that actually carries the code. The recipe uses two signals together — sender domain and a subject heuristic: app . post ( " /webhooks/otp " , 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 ; const sender = msg . from ?.[ 0 ]?. email ?? "" ; const subject = msg . subject ?? "" ; const senderMatches = sender . endsWith ( " @no-reply.example.com " ); const subjectLooksRight = /code|verif|one. ? time|passcode/i . test ( subject ); if ( ! senderMatches || ! subjectLooksRight ) return ; await handleOtp ( msg . id ); }); Neither check alone is enough. Sender-only matching trips on welcome emails from the same domain; subject-only matching trips on anything that mentions "verification." Regex first, LLM second Most OTP emails follow one of a few shapes: a standalone 4–8 digit number, or a code after a label like "Your code is:". Three patterns, tried in order from most to least specific, cover the vast majority of services: const patterns = [ / (?: code|passcode|one [\s - ]? time )[^\d]{0,20}(\d{4,8}) /i , // "Your code
AI 资讯
Ephemeral Inboxes: Spin Up a Mailbox Per Test Run
Two CI workers kick off at the same moment. Both sign up a test user, both poll the shared QA Gmail account for "the" verification email, and worker #7 grabs the message that belonged to worker #12. The test passes. The wrong test. You spend an afternoon staring at a green build that should've been red. Shared inboxes are the single biggest source of flakiness in email-dependent E2E tests, and every workaround — catch-all forwarding rules, label rules scoped per PR, OAuth tokens living on the runner — adds another moving part that breaks on its own schedule. The fix is structural: every test gets its own address, on infrastructure your suite provisions and destroys. One wildcard, infinite addresses The E2E email testing recipe sets this up with one CLI command: nylas inbound create e2e You get back an inbox ID and a wildcard pattern shaped like e2e-*@yourapp.nylas.email . From there, each test mints a unique address under the wildcard — e2e-<uuid>@yourapp.nylas.email — and there's nothing to provision per address. You don't pay or configure per address either; the wildcard is just a convention, so burn UUIDs freely. Mail flows through MX records hosted on the Nylas side, which means zero DNS work in your own zone (the tradeoff: addresses live under *.nylas.email ). The Playwright fixture is two pieces — an address minter and a poller: export const test = base . extend < Fixtures > ({ testEmail : async ({}, use ) => { await use ( `e2e- ${ randomUUID ()} @yourapp.nylas.email` ); }, pollInbox : async ({ testEmail }, use ) => { const poll = async ( timeoutMs = 30 _000 ) => { const deadline = Date . now () + timeoutMs ; while ( Date . now () < deadline ) { const out = execSync ( `nylas inbound messages ${ process . env . INBOX_ID } --json --limit 50` , ). toString (); const match = JSON . parse ( out ). find (( m ) => m . to . some (( t ) => t . email === testEmail ), ); if ( match ) return match ; await new Promise (( r ) => setTimeout ( r , 1500 )); } throw new Error (
AI 资讯
A Sales Outreach Agent That Owns Its Email Address
200 messages per account per day. That's the free-plan send ceiling on a Nylas Agent Account , and it's a surprisingly useful number to design an outreach agent around — it forces the kind of pacing that keeps cold email from becoming spam, and paid plans drop the daily cap by default when you outgrow it. The bigger idea: instead of sending campaigns through a rep's mailbox or a send-only API, the agent gets its own address. sales-agent@yourcompany.com is a real mailbox — it sends, it receives replies, it owns a calendar. Agent Accounts are in beta, but the model is straightforward: each account is just another grant, so the Messages, Threads, Events, and Webhooks endpoints you'd use for a connected Gmail account work unchanged. What the loop looks like The sales-outreach pattern from the product docs runs in three stages, all on one grant_id : Send the campaign through the standard send endpoint. Classify replies with an LLM into interested / not now / unsubscribe , threading every exchange through the Messages API. Book the meeting — when a prospect says yes, the same grant creates an event on the agent's own calendar and sends the invite. No CRM hand-offs between three tools, no rep mailbox cluttered with sequence noise. Replies arrive as webhooks Inbound mail fires message.created , and the payload looks exactly like it does for any other grant. One subscription covers your whole application: curl --request POST \ --url 'https://api.us.nylas.com/v3/webhooks/' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer <NYLAS_API_KEY>' \ --data-raw '{ "trigger_types": ["message.created", "event.created", "event.updated"], "description": "Outreach agent", "webhook_url": "https://your-app.example.com/webhooks/nylas", "notification_email_addresses": ["dev-team@your-company.com"] }' Your endpoint gets a GET with a challenge query parameter first — echo it back in a 200 and deliveries start flowing as POST s. The payload's data.object carries sender,
AI 资讯
Build an Email Support Triage Agent With Its Own Inbox
Every shared support inbox eventually becomes a triage problem: 80 unread messages, no agreement on what "urgent" means, and the one person who knows which customer is about to churn is on PTO. Teams keep solving this with labels and heroics. It's a better fit for an LLM — as long as the LLM has somewhere safe to live. That's the case for giving the triage agent its own mailbox. Nylas Agent Accounts (currently in beta) are hosted mailboxes you create entirely through the API. A support@yourcompany.com Agent Account receives every inbound support email, gets six system folders out of the box ( inbox , sent , drafts , trash , junk , archive ), and exposes the same grant_id -based endpoints as any connected Gmail or Outlook account. Creating one is a single request: 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": "support@yourcompany.com" } }' Save the grant_id from the response — every other call hangs off it. Four buckets beat five The classification scheme from the email triage agent recipe sorts mail into exactly four categories: Bucket Meaning Action URGENT Production incident, executive ask Draft a reply within the hour ACTION Code review, meeting follow-up Draft a reply same-day FYI Status update Leave it alone NOISE Newsletter, automated alert Archive Four is deliberate. Three loses fidelity — everything collapses into "important." Five and the model starts confusing adjacent categories. The prompt runs with temperature=0 and max_tokens=10 , and the model only sees sender + subject + a 200-character snippet, not the full body. That's enough for over 90% accuracy. Here's the prompt verbatim from the recipe: You triage email into one of four categories: URGENT — production incidents, executive requests; reply within 1 hour ACTION — code reviews, meeting follow-ups; reply same day FYI — info
AI 资讯
Give Your AI Agent Its Own Email Address (Not Access to Yours)
Most "AI agent + email" tutorials start the same way: connect the agent to a human's inbox over OAuth, hope the token doesn't expire mid-run, and pray the agent never replies to the wrong thread on someone's behalf. There's a different model: give the agent its own email address. Nylas recently shipped Agent Accounts (currently in beta) — fully functional, Nylas-hosted mailboxes you create and control entirely through the API. Each one is a real name@company.com address that sends, receives, hosts calendar events, and RSVPs to invitations. To anyone interacting with it, it's indistinguishable from a human-operated account. I work on the docs at Nylas, so I've spent a lot of time with this API. Here's a tour of what it does and how to get a mailbox running in a few minutes. Why not just connect the agent to a human inbox? You can — that's what OAuth grants are for, and they're the right tool when the agent works on behalf of a person. But a lot of agent workflows want a first-class identity instead: System mailboxes ( sales@ , support@ , scheduling@ ) that your app owns end-to-end. No OAuth consent screen, no user offboarding breaking your integration. Ephemeral inboxes for test automation — provision a fresh address per run, sign up for a service, grab the OTP from the verification email, tear it down. Per-customer identities in multi-tenant apps: scheduling@customer-a.com , scheduling@customer-b.com , each with its own send quota and sender reputation, all in one Nylas application. A scheduling bot with its own calendar that proposes slots, sends invites, and shows up as a normal participant in Google Calendar, Microsoft 365, and Apple Calendar. The key design decision: an Agent Account is just another grant . It gets a grant_id that works with every existing Nylas endpoint — Messages, Drafts, Threads, Folders, Attachments, Calendars, Events, Webhooks. If you've already built against connected accounts, nothing new to learn. Create a mailbox with one API call Every