[{"data":1,"prerenderedAt":517},["ShallowReactive",2],{"navigation":3,"\u002Fdocs\u002Fguides\u002Fagents\u002F":72,"\u002Fdocs\u002Fguides\u002Fagents\u002F-surround":513},[4,8,22,26,43],{"title":5,"path":6,"stem":7},"Getting Started","\u002Fdocs\u002Fgetting-started","1.docs\u002F1.getting-started",{"title":9,"path":10,"stem":11,"children":12,"page":21},"Setup","\u002Fdocs\u002Fsetup","1.docs\u002F2.setup",[13,17],{"title":14,"path":15,"stem":16},"Domain","\u002Fdocs\u002Fsetup\u002Fdomain","1.docs\u002F2.setup\u002F2.domain",{"title":18,"path":19,"stem":20},"Email","\u002Fdocs\u002Fsetup\u002Faccount","1.docs\u002F2.setup\u002F3.account",false,{"title":23,"path":24,"stem":25},"Email Testing API","\u002Fdocs\u002Fapi","1.docs\u002F3.api",{"title":27,"path":28,"stem":29,"children":30,"page":21},"Features","\u002Fdocs\u002Ffeatures","1.docs\u002F4.features",[31,35,39],{"title":32,"path":33,"stem":34},"Account","\u002Fdocs\u002Ffeatures\u002Faccount","1.docs\u002F4.features\u002F1.account",{"title":36,"path":37,"stem":38},"Mailbox","\u002Fdocs\u002Ffeatures\u002Fmailbox","1.docs\u002F4.features\u002F2.mailbox",{"title":40,"path":41,"stem":42},"Messages","\u002Fdocs\u002Ffeatures\u002Fmessage","1.docs\u002F4.features\u002F3.message",{"title":44,"path":45,"stem":46,"children":47,"page":21},"Guides","\u002Fdocs\u002Fguides","1.docs\u002F5.guides",[48,52,56,60,64,68],{"title":49,"path":50,"stem":51},"CI","\u002Fdocs\u002Fguides\u002Fci","1.docs\u002F5.guides\u002F1.ci",{"title":53,"path":54,"stem":55},"Catch-All","\u002Fdocs\u002Fguides\u002Fcatch-all","1.docs\u002F5.guides\u002F2.catch-all",{"title":57,"path":58,"stem":59},"SPF, DKIM, DMARC","\u002Fdocs\u002Fguides\u002Fspf-dkim-dmarc","1.docs\u002F5.guides\u002F3.spf-dkim-dmarc",{"title":61,"path":62,"stem":63},"E2E Flows","\u002Fdocs\u002Fguides\u002Fe2e","1.docs\u002F5.guides\u002F4.e2e",{"title":65,"path":66,"stem":67},"Email Clients","\u002Fdocs\u002Fguides\u002Femail-clients","1.docs\u002F5.guides\u002F5.email-clients",{"title":69,"path":70,"stem":71},"AI Agents","\u002Fdocs\u002Fguides\u002Fagents","1.docs\u002F5.guides\u002F6.agents",{"id":73,"title":74,"body":75,"description":507,"extension":508,"meta":509,"navigation":510,"path":70,"seo":511,"stem":71,"__hash__":512},"docs\u002F1.docs\u002F5.guides\u002F6.agents.md","Test Inboxes for AI Agents",{"type":76,"value":77,"toc":497},"minimark",[78,82,86,129,133,140,198,201,205,219,457,465,469,486,490,493],[79,80,81],"p",{},"An agent that exercises your signup flow needs to receive real email: the verification code, the confirmation link, the welcome message. In development that mail shouldn't land in your inbox, and the agent shouldn't be anywhere near production mailboxes. A sandbox domain gives every run its own address, and the API gives the agent a way to read what arrived.",[83,84,9],"h2",{"id":85},"setup",[87,88,90,95,113,117],"steps",{"level":89},"3",[91,92,94],"h3",{"id":93},"create-a-catch-all-account-on-a-dev-domain","Create a catch-all account on a dev domain",[79,96,97,98,102,103,106,107,112],{},"Username ",[99,100,101],"code",{},"*"," on e.g. ",[99,104,105],{},"dev.example.com"," - ",[108,109,111],"a",{"href":110},"\u002Fdocs\u002Ffeatures\u002Faccount#catch-all-addresses","how catch-all works",". Every address on the domain is now deliverable without creating accounts.",[91,114,116],{"id":115},"create-an-api-token-for-the-agent","Create an API token for the agent",[79,118,119,120,124,125,128],{},"On the ",[108,121,123],{"href":122},"\u002Ftokens","API Keys"," page. The agent authenticates every request with the ",[99,126,127],{},"X-API-KEY"," header.",[83,130,132],{"id":131},"a-fresh-address-per-run","A Fresh Address per Run",[79,134,135,136,139],{},"Derive the address from the run, same as the ",[108,137,138],{"href":54},"QA pattern",":",[141,142,147],"pre",{"className":143,"code":144,"language":145,"meta":146,"style":146},"language-js shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","const address = `agent-${crypto.randomUUID()}@dev.example.com`\n","js","",[99,148,149],{"__ignoreMap":146},[150,151,154,158,162,166,169,173,176,179,182,186,189,192,195],"span",{"class":152,"line":153},"line",1,[150,155,157],{"class":156},"spNyl","const",[150,159,161],{"class":160},"sTEyZ"," address ",[150,163,165],{"class":164},"sMK4o","=",[150,167,168],{"class":164}," `",[150,170,172],{"class":171},"sfazB","agent-",[150,174,175],{"class":164},"${",[150,177,178],{"class":160},"crypto",[150,180,181],{"class":164},".",[150,183,185],{"class":184},"s2Zo4","randomUUID",[150,187,188],{"class":160},"()",[150,190,191],{"class":164},"}",[150,193,194],{"class":171},"@dev.example.com",[150,196,197],{"class":164},"`\n",[79,199,200],{},"The agent signs up with it, and the mail lands in the catch-all's INBOX.",[83,202,204],{"id":203},"reading-the-otp","Reading the OTP",[79,206,207,210,211,214,215,218],{},[99,208,209],{},"inboxOf"," and ",[99,212,213],{},"waitForMessage"," are the polling helpers from the ",[108,216,217],{"href":50},"CI guide",". The catch-all holds mail for the whole domain, so match on the recipient:",[141,220,222],{"className":143,"code":221,"language":145,"meta":146,"style":146},"const inbox = await inboxOf('*@dev.example.com')\n\nconst message = await waitForMessage(\n  inbox,\n  m => m.to.some(t => t.address === address),\n)\n\nconst otp = message.text.match(\u002F\\b\\d{6}\\b\u002F)?.[0]\nconst link = message.text.match(\u002Fhttps?:\\\u002F\\\u002F\\S*confirm\\S*\u002F)?.[0]\n",[99,223,224,254,261,279,288,334,339,344,401],{"__ignoreMap":146},[150,225,226,228,231,233,237,240,243,246,249,251],{"class":152,"line":153},[150,227,157],{"class":156},[150,229,230],{"class":160}," inbox ",[150,232,165],{"class":164},[150,234,236],{"class":235},"s7zQu"," await",[150,238,239],{"class":184}," inboxOf",[150,241,242],{"class":160},"(",[150,244,245],{"class":164},"'",[150,247,248],{"class":171},"*@dev.example.com",[150,250,245],{"class":164},[150,252,253],{"class":160},")\n",[150,255,257],{"class":152,"line":256},2,[150,258,260],{"emptyLinePlaceholder":259},true,"\n",[150,262,264,266,269,271,273,276],{"class":152,"line":263},3,[150,265,157],{"class":156},[150,267,268],{"class":160}," message ",[150,270,165],{"class":164},[150,272,236],{"class":235},[150,274,275],{"class":184}," waitForMessage",[150,277,278],{"class":160},"(\n",[150,280,282,285],{"class":152,"line":281},4,[150,283,284],{"class":160},"  inbox",[150,286,287],{"class":164},",\n",[150,289,291,295,298,301,303,306,308,311,313,316,318,321,323,326,329,332],{"class":152,"line":290},5,[150,292,294],{"class":293},"sHdIc","  m",[150,296,297],{"class":156}," =>",[150,299,300],{"class":160}," m",[150,302,181],{"class":164},[150,304,305],{"class":160},"to",[150,307,181],{"class":164},[150,309,310],{"class":184},"some",[150,312,242],{"class":160},[150,314,315],{"class":293},"t",[150,317,297],{"class":156},[150,319,320],{"class":160}," t",[150,322,181],{"class":164},[150,324,325],{"class":160},"address ",[150,327,328],{"class":164},"===",[150,330,331],{"class":160}," address)",[150,333,287],{"class":164},[150,335,337],{"class":152,"line":336},6,[150,338,253],{"class":160},[150,340,342],{"class":152,"line":341},7,[150,343,260],{"emptyLinePlaceholder":259},[150,345,347,349,352,354,357,359,362,364,367,369,372,375,378,381,383,385,388,391,394,398],{"class":152,"line":346},8,[150,348,157],{"class":156},[150,350,351],{"class":160}," otp ",[150,353,165],{"class":164},[150,355,356],{"class":160}," message",[150,358,181],{"class":164},[150,360,361],{"class":160},"text",[150,363,181],{"class":164},[150,365,366],{"class":184},"match",[150,368,242],{"class":160},[150,370,371],{"class":164},"\u002F",[150,373,374],{"class":235},"\\b",[150,376,377],{"class":171},"\\d",[150,379,380],{"class":164},"{6}",[150,382,374],{"class":235},[150,384,371],{"class":164},[150,386,387],{"class":160},")",[150,389,390],{"class":164},"?.",[150,392,393],{"class":160},"[",[150,395,397],{"class":396},"sbssI","0",[150,399,400],{"class":160},"]\n",[150,402,404,406,409,411,413,415,417,419,421,423,425,428,431,433,436,439,441,444,447,449,451,453,455],{"class":152,"line":403},9,[150,405,157],{"class":156},[150,407,408],{"class":160}," link ",[150,410,165],{"class":164},[150,412,356],{"class":160},[150,414,181],{"class":164},[150,416,361],{"class":160},[150,418,181],{"class":164},[150,420,366],{"class":184},[150,422,242],{"class":160},[150,424,371],{"class":164},[150,426,427],{"class":171},"https",[150,429,430],{"class":164},"?",[150,432,139],{"class":171},[150,434,435],{"class":160},"\\\u002F\\\u002F",[150,437,438],{"class":171},"\\S",[150,440,101],{"class":164},[150,442,443],{"class":171},"confirm\\S",[150,445,446],{"class":164},"*\u002F",[150,448,387],{"class":160},[150,450,390],{"class":164},[150,452,393],{"class":160},[150,454,397],{"class":396},[150,456,400],{"class":160},[79,458,459,460,464],{},"For a long-running agent, skip polling: ",[108,461,463],{"href":462},"\u002Fdocs\u002Fapi#real-time-updates","subscribe over SSE"," and hold one connection instead of hammering the list endpoint.",[83,466,468],{"id":467},"for-the-agent-itself","For the Agent Itself",[79,470,471,472,475,476,479,480,181],{},"The docs are agent-readable. ",[99,473,474],{},"https:\u002F\u002Fsmtp.dev\u002Fllms.txt"," indexes the site, and any docs page serves markdown when you append ",[99,477,478],{},".md"," to its URL. The full API surface is in the ",[108,481,485],{"href":482,"rel":483},"https:\u002F\u002Fapi.smtp.dev\u002Fdocs.jsonld",[484],"nofollow","OpenAPI document",[83,487,489],{"id":488},"boundaries","Boundaries",[79,491,492],{},"Receiving is unrestricted: sandbox domains have real MX records, so any service the agent signs up for can deliver to them. Outbound is the opposite - mail from the sandbox only delivers to accounts inside it. An agent with sandbox credentials can read everything on your test domain and email nobody else, which is exactly the blast radius you want while it's under development.",[494,495,496],"style",{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":146,"searchDepth":256,"depth":256,"links":498},[499,503,504,505,506],{"id":85,"depth":256,"text":9,"children":500},[501,502],{"id":93,"depth":263,"text":94},{"id":115,"depth":263,"text":116},{"id":131,"depth":256,"text":132},{"id":203,"depth":256,"text":204},{"id":467,"depth":256,"text":468},{"id":488,"depth":256,"text":489},"Give an agent a fresh address per run, read OTP codes and confirmation links over the REST API, and keep agent mail out of real inboxes.","md",{},{"title":69},{"title":74,"description":507},"pDxjgxSko-xgzLGwrFTwnAV79jbycrYBzPFMvgiUzis",[514,516],{"title":65,"path":66,"stem":67,"description":515,"children":-1},"Connect a real client over IMAP to see how multipart emails render outside the browser. Host, port, and login settings for any client.",null,1784164786999]