[{"data":1,"prerenderedAt":1242},["ShallowReactive",2],{"navigation:en":3,"\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Femails:en":311},[4],{"title":5,"path":6,"stem":7,"children":8,"icon":10},"Nuxfire Docs","\u002Fdocs","docs\u002F0.index",[9,11,152],{"title":5,"path":6,"stem":7,"icon":10},"i-lucide-layout-grid",{"title":12,"path":13,"stem":14,"children":15,"icon":151},"SaaS Starter Kit","\u002Fdocs\u002Fsaas-starter-kit","docs\u002F1.saas-starter-kit\u002F0.index",[16,19,63,129],{"title":17,"path":13,"stem":14,"icon":18},"What is the SaaS Starter Kit?","i-lucide-info",{"title":20,"icon":21,"hide":22,"path":23,"stem":24,"children":25,"page":62},"Getting Started","i-lucide-play",true,"\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started","docs\u002F1.saas-starter-kit\u002F1.getting-started",[26,30,34,38,42,46,50,54,58],{"title":27,"path":28,"stem":29},"Quick Start","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fquick-start","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F0.quick-start",{"title":31,"path":32,"stem":33},"Installation","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Finstallation","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F1.installation",{"title":35,"path":36,"stem":37},"Cloudflare Access","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fcloudflare-access","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F2.cloudflare-access",{"title":39,"path":40,"stem":41},"Configuration","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fconfiguration","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F3.configuration",{"title":43,"path":44,"stem":45},"Secrets","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fsecrets","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F4.secrets",{"title":47,"path":48,"stem":49},"Environment Variables","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fenvironment-variables","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F5.environment-variables",{"title":51,"path":52,"stem":53},"Deploy","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fdeploy","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F6.deploy",{"title":55,"path":56,"stem":57},"Local Development","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Flocal-development","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F7.local-development",{"title":59,"path":60,"stem":61},"Project Structure","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fproject-structure","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F8.project-structure",false,{"title":64,"icon":65,"hide":22,"path":66,"stem":67,"children":68,"page":62},"Features","i-lucide-box","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures","docs\u002F1.saas-starter-kit\u002F2.features",[69,73,77,81,85,89,93,97,101,105,109,113,117,121,125],{"title":70,"path":71,"stem":72},"Authentication","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fauth","docs\u002F1.saas-starter-kit\u002F2.features\u002F1.auth",{"title":74,"path":75,"stem":76},"Rate Limiting","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Frate-limiting","docs\u002F1.saas-starter-kit\u002F2.features\u002F10.rate-limiting",{"title":78,"path":79,"stem":80},"WebSockets","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fwebsockets","docs\u002F1.saas-starter-kit\u002F2.features\u002F11.websockets",{"title":82,"path":83,"stem":84},"Blog","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fblog","docs\u002F1.saas-starter-kit\u002F2.features\u002F14.blog",{"title":86,"path":87,"stem":88},"Documentation","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fdocumentation","docs\u002F1.saas-starter-kit\u002F2.features\u002F15.documentation",{"title":90,"path":91,"stem":92},"Analytics","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fanalytics","docs\u002F1.saas-starter-kit\u002F2.features\u002F16.analytics",{"title":94,"path":95,"stem":96},"Platform Admin Console","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fplatform-admin","docs\u002F1.saas-starter-kit\u002F2.features\u002F17.platform-admin",{"title":98,"path":99,"stem":100},"Database","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fdatabase","docs\u002F1.saas-starter-kit\u002F2.features\u002F2.database",{"title":102,"path":103,"stem":104},"Payments & Billing","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fpayments","docs\u002F1.saas-starter-kit\u002F2.features\u002F3.payments",{"title":106,"path":107,"stem":108},"Emails","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Femails","docs\u002F1.saas-starter-kit\u002F2.features\u002F4.emails",{"title":110,"path":111,"stem":112},"Notifications","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fnotifications","docs\u002F1.saas-starter-kit\u002F2.features\u002F5.notifications",{"title":114,"path":115,"stem":116},"Role-Based Access Control","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Frbac","docs\u002F1.saas-starter-kit\u002F2.features\u002F6.rbac",{"title":118,"path":119,"stem":120},"Async Jobs","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fasync-jobs","docs\u002F1.saas-starter-kit\u002F2.features\u002F7.async-jobs",{"title":122,"path":123,"stem":124},"Storage","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fstorage","docs\u002F1.saas-starter-kit\u002F2.features\u002F8.storage",{"title":126,"path":127,"stem":128},"Internationalization","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Finternationalization","docs\u002F1.saas-starter-kit\u002F2.features\u002F9.internationalization",{"title":130,"icon":131,"path":132,"stem":133,"children":134,"page":62},"Concepts","i-lucide-graduation-cap","\u002Fdocs\u002Fsaas-starter-kit\u002Fconcepts","docs\u002F1.saas-starter-kit\u002F3.concepts",[135,139,143,147],{"title":136,"path":137,"stem":138},"Technology Stack","\u002Fdocs\u002Fsaas-starter-kit\u002Fconcepts\u002Ftech-stack","docs\u002F1.saas-starter-kit\u002F3.concepts\u002F0.tech-stack",{"title":140,"path":141,"stem":142},"SST.dev","\u002Fdocs\u002Fsaas-starter-kit\u002Fconcepts\u002Fsst","docs\u002F1.saas-starter-kit\u002F3.concepts\u002F1.sst",{"title":144,"path":145,"stem":146},"NuxtHub","\u002Fdocs\u002Fsaas-starter-kit\u002Fconcepts\u002Fnuxt-hub","docs\u002F1.saas-starter-kit\u002F3.concepts\u002F2.nuxt-hub",{"title":148,"path":149,"stem":150},"Design System & Branding","\u002Fdocs\u002Fsaas-starter-kit\u002Fconcepts\u002Fdesign-system","docs\u002F1.saas-starter-kit\u002F3.concepts\u002F3.design-system","i-lucide-zap",{"title":153,"path":154,"stem":155,"children":156,"icon":159},"Fireskills","\u002Fdocs\u002Ffireskills","docs\u002F2.fireskills\u002F0.index",[157,160,219,249,275,293],{"title":158,"path":154,"stem":155,"icon":159},"What is Fireskills?","i-lucide-flame",{"title":20,"icon":21,"hide":22,"path":161,"stem":162,"children":163,"page":62},"\u002Fdocs\u002Ffireskills\u002Fgetting-started","docs\u002F2.fireskills\u002F1.getting-started",[164,167,171,175,179,183,187,191,195,199,203,207,211,215],{"title":27,"path":165,"stem":166},"\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fquick-start","docs\u002F2.fireskills\u002F1.getting-started\u002F00.quick-start",{"title":168,"path":169,"stem":170},"Workflow & Governance","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fworkflow","docs\u002F2.fireskills\u002F1.getting-started\u002F01.workflow",{"title":172,"path":173,"stem":174},"Project Context","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fproject-context","docs\u002F2.fireskills\u002F1.getting-started\u002F02.project-context",{"title":176,"path":177,"stem":178},"Step 0: Setup","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-setup","docs\u002F2.fireskills\u002F1.getting-started\u002F03.step-setup",{"title":180,"path":181,"stem":182},"Step 1: Inbox","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-inbox","docs\u002F2.fireskills\u002F1.getting-started\u002F04.step-inbox",{"title":184,"path":185,"stem":186},"Step 2: Backlog","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-backlog","docs\u002F2.fireskills\u002F1.getting-started\u002F05.step-backlog",{"title":188,"path":189,"stem":190},"Step 3: Specify","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-specify","docs\u002F2.fireskills\u002F1.getting-started\u002F06.step-specify",{"title":192,"path":193,"stem":194},"Step 4: Validate","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-validate","docs\u002F2.fireskills\u002F1.getting-started\u002F07.step-validate",{"title":196,"path":197,"stem":198},"Step 5: Tasks","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-tasks","docs\u002F2.fireskills\u002F1.getting-started\u002F08.step-tasks",{"title":200,"path":201,"stem":202},"Step 6: TDD\u002FBDD","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-tdd-bdd","docs\u002F2.fireskills\u002F1.getting-started\u002F09.step-tdd-bdd",{"title":204,"path":205,"stem":206},"Step 7: Implement","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-implement","docs\u002F2.fireskills\u002F1.getting-started\u002F10.step-implement",{"title":208,"path":209,"stem":210},"Step 8: Documentator","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-documentator","docs\u002F2.fireskills\u002F1.getting-started\u002F11.step-documentator",{"title":212,"path":213,"stem":214},"Late Changes","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Flate-changes","docs\u002F2.fireskills\u002F1.getting-started\u002F12.late-changes",{"title":216,"path":217,"stem":218},"Other Entry Points","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fother-entry-points","docs\u002F2.fireskills\u002F1.getting-started\u002F13.other-entry-points",{"title":220,"icon":221,"hide":22,"path":222,"stem":223,"children":224,"page":62},"Methodology","i-lucide-git-branch","\u002Fdocs\u002Ffireskills\u002Fmethodology","docs\u002F2.fireskills\u002F2.methodology",[225,229,233,237,241,245],{"title":226,"path":227,"stem":228},"The Three Acts","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Fthree-acts","docs\u002F2.fireskills\u002F2.methodology\u002F0.three-acts",{"title":230,"path":231,"stem":232},"The Three Gates","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Fthree-gates","docs\u002F2.fireskills\u002F2.methodology\u002F1.three-gates",{"title":234,"path":235,"stem":236},"The Canonical Spec","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Fcanonical-spec","docs\u002F2.fireskills\u002F2.methodology\u002F2.canonical-spec",{"title":238,"path":239,"stem":240},"Lifecycle States","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Flifecycle-states","docs\u002F2.fireskills\u002F2.methodology\u002F3.lifecycle-states",{"title":242,"path":243,"stem":244},"Effort Scale","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Feffort-scale","docs\u002F2.fireskills\u002F2.methodology\u002F4.effort-scale",{"title":246,"path":247,"stem":248},"Milestones & Governance","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Fgovernance-and-milestones","docs\u002F2.fireskills\u002F2.methodology\u002F5.governance-and-milestones",{"title":250,"icon":251,"hide":22,"path":252,"stem":253,"children":254,"page":62},"Skills","i-lucide-layers","\u002Fdocs\u002Ffireskills\u002Fskills","docs\u002F2.fireskills\u002F3.skills",[255,259,263,267,271],{"title":256,"path":257,"stem":258},"Catalog","\u002Fdocs\u002Ffireskills\u002Fskills\u002Fcatalog","docs\u002F2.fireskills\u002F3.skills\u002F0.catalog",{"title":260,"path":261,"stem":262},"Act I: Define","\u002Fdocs\u002Ffireskills\u002Fskills\u002Fact-1-define","docs\u002F2.fireskills\u002F3.skills\u002F1.act-1-define",{"title":264,"path":265,"stem":266},"Act II: Design & Prove","\u002Fdocs\u002Ffireskills\u002Fskills\u002Fact-2-design-prove","docs\u002F2.fireskills\u002F3.skills\u002F2.act-2-design-prove",{"title":268,"path":269,"stem":270},"Act III: Deliver","\u002Fdocs\u002Ffireskills\u002Fskills\u002Fact-3-deliver","docs\u002F2.fireskills\u002F3.skills\u002F3.act-3-deliver",{"title":272,"path":273,"stem":274},"Governance & Decisions","\u002Fdocs\u002Ffireskills\u002Fskills\u002Fgovernance-and-decisions","docs\u002F2.fireskills\u002F3.skills\u002F4.governance-and-decisions",{"title":276,"icon":277,"hide":22,"path":278,"stem":279,"children":280,"page":62},"Specialists","i-lucide-sparkles","\u002Fdocs\u002Ffireskills\u002Fspecialists","docs\u002F2.fireskills\u002F4.specialists",[281,285,289],{"title":282,"path":283,"stem":284},"Overview","\u002Fdocs\u002Ffireskills\u002Fspecialists\u002Foverview","docs\u002F2.fireskills\u002F4.specialists\u002F0.overview",{"title":286,"path":287,"stem":288},"Nuxfire Stack","\u002Fdocs\u002Ffireskills\u002Fspecialists\u002Fnuxfire-stack","docs\u002F2.fireskills\u002F4.specialists\u002F1.nuxfire-stack",{"title":290,"path":291,"stem":292},"Engineering Specialists","\u002Fdocs\u002Ffireskills\u002Fspecialists\u002Fengineering-specialists","docs\u002F2.fireskills\u002F4.specialists\u002F2.engineering-specialists",{"title":294,"icon":295,"hide":22,"path":296,"stem":297,"children":298,"page":62},"CLI & Tooling","i-lucide-terminal","\u002Fdocs\u002Ffireskills\u002Fcli","docs\u002F2.fireskills\u002F5.cli",[299,303,307],{"title":300,"path":301,"stem":302},"CLI Overview","\u002Fdocs\u002Ffireskills\u002Fcli\u002Foverview","docs\u002F2.fireskills\u002F5.cli\u002F0.overview",{"title":304,"path":305,"stem":306},"Commands","\u002Fdocs\u002Ffireskills\u002Fcli\u002Fcommands","docs\u002F2.fireskills\u002F5.cli\u002F1.commands",{"title":308,"path":309,"stem":310},"Safety Scripts","\u002Fdocs\u002Ffireskills\u002Fcli\u002Fgovernance-scripts","docs\u002F2.fireskills\u002F5.cli\u002F2.governance-scripts",{"id":312,"title":106,"body":313,"description":1237,"extension":1238,"meta":1239,"navigation":22,"path":107,"seo":1240,"stem":108,"__hash__":1241},"docs\u002Fdocs\u002F1.saas-starter-kit\u002F2.features\u002F4.emails.md",{"type":314,"value":315,"toc":1230},"minimark",[316,337,342,387,390,397,487,508,512,525,540,667,916,944,948,997,1001,1008,1152,1159,1226],[317,318,319,320,327,328,332,333,336],"p",{},"Nuxfire ships with an email system that runs entirely on Cloudflare Workers, built on a vendored fork of ",[321,322,326],"a",{"href":323,"rel":324},"https:\u002F\u002Fadonisjs.com",[325],"nofollow","AdonisJS Mail"," adapted to run without the AdonisJS framework — ",[329,330,331],"code",{},"@nuxfire\u002Femails\u002Fmailer"," (",[329,334,335],{},"packages\u002Femails\u002Fmailer","), owned source rather than a dependency on a third-party fork.",[338,339,341],"h2",{"id":340},"architecture","Architecture",[343,344,345,361,369,378],"ul",{},[346,347,348,332,352,355,356],"li",{},[349,350,351],"strong",{},"Email Templates",[329,353,354],{},"packages\u002Femails\u002Ftemplates",") — type-safe templates using ",[321,357,360],{"href":358,"rel":359},"https:\u002F\u002Freact.email",[325],"React Email",[346,362,363,332,366,368],{},[349,364,365],{},"Mailer Engine",[329,367,335],{},") — the provider-agnostic send engine, a fork of AdonisJS Mail",[346,370,371,332,374,377],{},[349,372,373],{},"Email Worker",[329,375,376],{},"apps\u002Ffunctions\u002Fsrc\u002Femails.ts",") — a Cloudflare Worker Entrypoint that handles provider-agnostic sending",[346,379,380,332,383,386],{},[349,381,382],{},"Infrastructure",[329,384,385],{},"infra\u002Femails.ts",") — infra config for the Worker",[338,388,351],{"id":389},"email-templates",[317,391,392,393,396],{},"Templates are built with ",[321,394,360],{"href":358,"rel":395},[325]," and Tailwind. For example:",[398,399,405],"pre",{"className":400,"code":401,"filename":402,"language":403,"meta":404,"style":404},"language-tsx shiki shiki-themes material-theme-lighter github-light github-dark monokai","import { Body, Container, Html, Text } from \"@react-email\u002Fcomponents\";\n\nexport const WelcomeEmail = ({ username }: { username: string }) => (\n  \u003CHtml>\n    \u003CBody>\n      \u003CTailwind>\n        \u003CContainer class=\"p-4 border border-solid border-[#eaeaea] rounded my-[40px] mx-auto max-w-[465px]\">\n          \u003CText>Welcome {username}!\u003C\u002FText>\n        \u003C\u002FContainer>\n      \u003C\u002FTailwind>\n    \u003C\u002FBody>\n  \u003C\u002FHtml>\n);\n","packages\u002Femails\u002Ftemplates\u002FWelcome.tsx","tsx","",[329,406,407,415,421,427,433,439,445,451,457,463,469,475,481],{"__ignoreMap":404},[408,409,412],"span",{"class":410,"line":411},"line",1,[408,413,414],{},"import { Body, Container, Html, Text } from \"@react-email\u002Fcomponents\";\n",[408,416,418],{"class":410,"line":417},2,[408,419,420],{"emptyLinePlaceholder":22},"\n",[408,422,424],{"class":410,"line":423},3,[408,425,426],{},"export const WelcomeEmail = ({ username }: { username: string }) => (\n",[408,428,430],{"class":410,"line":429},4,[408,431,432],{},"  \u003CHtml>\n",[408,434,436],{"class":410,"line":435},5,[408,437,438],{},"    \u003CBody>\n",[408,440,442],{"class":410,"line":441},6,[408,443,444],{},"      \u003CTailwind>\n",[408,446,448],{"class":410,"line":447},7,[408,449,450],{},"        \u003CContainer class=\"p-4 border border-solid border-[#eaeaea] rounded my-[40px] mx-auto max-w-[465px]\">\n",[408,452,454],{"class":410,"line":453},8,[408,455,456],{},"          \u003CText>Welcome {username}!\u003C\u002FText>\n",[408,458,460],{"class":410,"line":459},9,[408,461,462],{},"        \u003C\u002FContainer>\n",[408,464,466],{"class":410,"line":465},10,[408,467,468],{},"      \u003C\u002FTailwind>\n",[408,470,472],{"class":410,"line":471},11,[408,473,474],{},"    \u003C\u002FBody>\n",[408,476,478],{"class":410,"line":477},12,[408,479,480],{},"  \u003C\u002FHtml>\n",[408,482,484],{"class":410,"line":483},13,[408,485,486],{},");\n",[317,488,489,490,332,493,496,497,500,501,496,504,507],{},"Every real template also receives the installation's ",[329,491,492],{},"brand",[329,494,495],{},"name"," and ",[329,498,499],{},"logoUrl",") as a second argument, built from your Branding — so subject lines and the logo follow your ",[329,502,503],{},"BRAND_NAME",[329,505,506],{},"BRAND_DOMAIN"," with nothing to edit in the templates.",[338,509,511],{"id":510},"provider-configuration","Provider Configuration",[317,513,514,515,518,519,521,522,524],{},"Who the email comes from is not configured here, and callers never pass it: the sender is your ",[329,516,517],{},"BRAND_EMAIL"," (shown as ",[329,520,503],{},"), set in the Branding section of the stage's env file and handed to the emails Worker at deploy time (",[329,523,385],{},"). The domain of that address must be verified in your email provider.",[317,526,527,528,531,532,535,536,539],{},"Email providers are enabled in ",[329,529,530],{},"config.ts","'s ",[329,533,534],{},"flags",", and wired up in the emails Worker itself. Only Resend is uncommented by default — the other transports are ready to enable, not deleted, with the exact import\u002Fconfig lines to uncomment marked ",[329,537,538],{},"TODO",":",[398,541,545],{"className":542,"code":543,"filename":530,"language":544,"meta":404,"style":404},"language-typescript shiki shiki-themes material-theme-lighter github-light github-dark monokai","export const flags: {\n  \u002F\u002F ...\n  resend?: boolean;\n  mailgun?: boolean;\n  ses?: boolean;\n  sparkPost?: boolean;\n  smtp?: boolean;\n} = {\n  \u002F\u002F ...\n  resend: true,\n};\n","typescript",[329,546,547,568,574,590,601,612,623,634,644,648,662],{"__ignoreMap":404},[408,548,549,553,557,561,564],{"class":410,"line":411},[408,550,552],{"class":551},"sRxSC","export",[408,554,556],{"class":555},"srJo8"," const",[408,558,560],{"class":559},"s91G_"," flags",[408,562,539],{"class":563},"sGXK2",[408,565,567],{"class":566},"swvn1"," {\n",[408,569,570],{"class":410,"line":417},[408,571,573],{"class":572},"ss7Ak","  \u002F\u002F ...\n",[408,575,576,580,583,587],{"class":410,"line":423},[408,577,579],{"class":578},"sIDdj","  resend",[408,581,582],{"class":563},"?:",[408,584,586],{"class":585},"s_MOj"," boolean",[408,588,589],{"class":566},";\n",[408,591,592,595,597,599],{"class":410,"line":429},[408,593,594],{"class":578},"  mailgun",[408,596,582],{"class":563},[408,598,586],{"class":585},[408,600,589],{"class":566},[408,602,603,606,608,610],{"class":410,"line":435},[408,604,605],{"class":578},"  ses",[408,607,582],{"class":563},[408,609,586],{"class":585},[408,611,589],{"class":566},[408,613,614,617,619,621],{"class":410,"line":441},[408,615,616],{"class":578},"  sparkPost",[408,618,582],{"class":563},[408,620,586],{"class":585},[408,622,589],{"class":566},[408,624,625,628,630,632],{"class":410,"line":447},[408,626,627],{"class":578},"  smtp",[408,629,582],{"class":563},[408,631,586],{"class":585},[408,633,589],{"class":566},[408,635,636,639,642],{"class":410,"line":453},[408,637,638],{"class":566},"}",[408,640,641],{"class":563}," =",[408,643,567],{"class":566},[408,645,646],{"class":410,"line":459},[408,647,573],{"class":572},[408,649,650,653,655,659],{"class":410,"line":465},[408,651,579],{"class":652},"squCx",[408,654,539],{"class":566},[408,656,658],{"class":657},"s8HiA"," true",[408,660,661],{"class":566},",\n",[408,663,664],{"class":410,"line":471},[408,665,666],{"class":566},"};\n",[398,668,670],{"className":542,"code":669,"filename":376,"language":544,"meta":404,"style":404},"\u002F\u002F TODO: import and set up email providers that you want to use\nimport { ResendTransport } from \"@nuxfire\u002Femails\u002Fmailer\u002Ftransports\u002Fresend\";\n\u002F\u002F import { MailgunTransport } from \"@nuxfire\u002Femails\u002Fmailer\u002Ftransports\u002Fmailgun\";\n\u002F\u002F ...\n\nconst config: Parameters\u003Ctypeof generateMailer>[0] = {\n  default: \"resend\",\n  mailers: {\n    ...(flags.resend && {\n      resend: () =>\n        new ResendTransport({\n          key: Resource.RESEND_API_KEY.value || \"\",\n          baseUrl: \"https:\u002F\u002Fapi.resend.com\",\n        }),\n    }),\n    \u002F\u002F ...(flags.mailgun && { mailgun: () => new MailgunTransport({ ... }) }),\n  },\n};\n",[329,671,672,677,708,713,718,722,763,779,788,807,821,834,862,878,889,899,905,911],{"__ignoreMap":404},[408,673,674],{"class":410,"line":411},[408,675,676],{"class":572},"\u002F\u002F TODO: import and set up email providers that you want to use\n",[408,678,679,682,685,689,692,695,699,703,706],{"class":410,"line":417},[408,680,681],{"class":551},"import",[408,683,684],{"class":566}," {",[408,686,688],{"class":687},"ss--_"," ResendTransport",[408,690,691],{"class":566}," }",[408,693,694],{"class":551}," from",[408,696,698],{"class":697},"siCPE"," \"",[408,700,702],{"class":701},"sLACW","@nuxfire\u002Femails\u002Fmailer\u002Ftransports\u002Fresend",[408,704,705],{"class":697},"\"",[408,707,589],{"class":566},[408,709,710],{"class":410,"line":423},[408,711,712],{"class":572},"\u002F\u002F import { MailgunTransport } from \"@nuxfire\u002Femails\u002Fmailer\u002Ftransports\u002Fmailgun\";\n",[408,714,715],{"class":410,"line":429},[408,716,717],{"class":572},"\u002F\u002F ...\n",[408,719,720],{"class":410,"line":435},[408,721,420],{"emptyLinePlaceholder":22},[408,723,724,727,730,732,736,739,742,745,748,751,755,758,761],{"class":410,"line":441},[408,725,726],{"class":555},"const",[408,728,729],{"class":559}," config",[408,731,539],{"class":563},[408,733,735],{"class":734},"sKvfc"," Parameters",[408,737,738],{"class":566},"\u003C",[408,740,741],{"class":563},"typeof",[408,743,744],{"class":687}," generateMailer",[408,746,747],{"class":566},">",[408,749,750],{"class":687},"[",[408,752,754],{"class":753},"sYThS","0",[408,756,757],{"class":687},"] ",[408,759,760],{"class":563},"=",[408,762,567],{"class":566},[408,764,765,768,770,772,775,777],{"class":410,"line":447},[408,766,767],{"class":652},"  default",[408,769,539],{"class":566},[408,771,698],{"class":697},[408,773,774],{"class":701},"resend",[408,776,705],{"class":697},[408,778,661],{"class":566},[408,780,781,784,786],{"class":410,"line":453},[408,782,783],{"class":652},"  mailers",[408,785,539],{"class":566},[408,787,567],{"class":566},[408,789,790,793,796,799,802,805],{"class":410,"line":459},[408,791,792],{"class":563},"    ...",[408,794,795],{"class":687},"(flags",[408,797,798],{"class":566},".",[408,800,801],{"class":687},"resend ",[408,803,804],{"class":563},"&&",[408,806,567],{"class":566},[408,808,809,813,815,818],{"class":410,"line":465},[408,810,812],{"class":811},"sD0ED","      resend",[408,814,539],{"class":566},[408,816,817],{"class":566}," ()",[408,819,820],{"class":555}," =>\n",[408,822,823,826,828,831],{"class":410,"line":471},[408,824,825],{"class":563},"        new",[408,827,688],{"class":811},[408,829,830],{"class":687},"(",[408,832,833],{"class":566},"{\n",[408,835,836,839,841,844,846,849,851,854,857,860],{"class":410,"line":477},[408,837,838],{"class":652},"          key",[408,840,539],{"class":566},[408,842,843],{"class":687}," Resource",[408,845,798],{"class":566},[408,847,848],{"class":559},"RESEND_API_KEY",[408,850,798],{"class":566},[408,852,853],{"class":687},"value ",[408,855,856],{"class":563},"||",[408,858,859],{"class":697}," \"\"",[408,861,661],{"class":566},[408,863,864,867,869,871,874,876],{"class":410,"line":483},[408,865,866],{"class":652},"          baseUrl",[408,868,539],{"class":566},[408,870,698],{"class":697},[408,872,873],{"class":701},"https:\u002F\u002Fapi.resend.com",[408,875,705],{"class":697},[408,877,661],{"class":566},[408,879,881,884,887],{"class":410,"line":880},14,[408,882,883],{"class":566},"        }",[408,885,886],{"class":687},")",[408,888,661],{"class":566},[408,890,892,895,897],{"class":410,"line":891},15,[408,893,894],{"class":566},"    }",[408,896,886],{"class":687},[408,898,661],{"class":566},[408,900,902],{"class":410,"line":901},16,[408,903,904],{"class":572},"    \u002F\u002F ...(flags.mailgun && { mailgun: () => new MailgunTransport({ ... }) }),\n",[408,906,908],{"class":410,"line":907},17,[408,909,910],{"class":566},"  },\n",[408,912,914],{"class":410,"line":913},18,[408,915,666],{"class":566},[317,917,918,921,922,924,925,928,929,932,933,936,937,940,941,798],{},[329,919,920],{},"Resource.RESEND_API_KEY"," matches the secret name exactly (",[329,923,848],{}," in ",[329,926,927],{},".env.example","\u002F",[329,930,931],{},"infra\u002Fsecret.ts",") — every provider secret follows this same ",[329,934,935],{},"SCREAMING_SNAKE_CASE"," naming, resolved through SST's own ",[329,938,939],{},"sst\u002Fresource"," binding rather than ",[329,942,943],{},"process.env",[338,945,947],{"id":946},"setting-up-secrets","Setting Up Secrets",[398,949,953],{"className":950,"code":951,"language":952,"meta":404,"style":404},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark monokai","# Resend\nsst secret set RESEND_API_KEY re_123...\n# Mailgun\nsst secret set MAILGUN_API_KEY key-123...\n","bash",[329,954,955,960,978,983],{"__ignoreMap":404},[408,956,957],{"class":410,"line":411},[408,958,959],{"class":572},"# Resend\n",[408,961,962,966,969,972,975],{"class":410,"line":417},[408,963,965],{"class":964},"sR7ES","sst",[408,967,968],{"class":701}," secret",[408,970,971],{"class":701}," set",[408,973,974],{"class":701}," RESEND_API_KEY",[408,976,977],{"class":701}," re_123...\n",[408,979,980],{"class":410,"line":423},[408,981,982],{"class":572},"# Mailgun\n",[408,984,985,987,989,991,994],{"class":410,"line":429},[408,986,965],{"class":964},[408,988,968],{"class":701},[408,990,971],{"class":701},[408,992,993],{"class":701}," MAILGUN_API_KEY",[408,995,996],{"class":701}," key-123...\n",[338,998,1000],{"id":999},"sending-emails","Sending Emails",[317,1002,1003,1004,1007],{},"Use the ",[329,1005,1006],{},"sendEmail"," function from the tRPC context to send emails:",[398,1009,1011],{"className":542,"code":1010,"language":544,"meta":404,"style":404},"async ({ ctx: { user, origin, authorize, sendEmail }, input }) => {\n  \u002F\u002F ...\n  await sendEmail(invite.email, \"Invitation\", {\n    teamName: team.name,\n    invitedBy: user.name,\n    inviteLink,\n  });\n  \u002F\u002F ...\n};\n",[329,1012,1013,1063,1067,1097,1113,1128,1135,1144,1148],{"__ignoreMap":404},[408,1014,1015,1019,1022,1025,1027,1029,1033,1036,1039,1041,1044,1046,1049,1052,1055,1058,1061],{"class":410,"line":411},[408,1016,1018],{"class":1017},"sTNss","async",[408,1020,1021],{"class":566}," ({",[408,1023,1024],{"class":578}," ctx",[408,1026,539],{"class":566},[408,1028,684],{"class":566},[408,1030,1032],{"class":1031},"sQgqH"," user",[408,1034,1035],{"class":566},",",[408,1037,1038],{"class":1031}," origin",[408,1040,1035],{"class":566},[408,1042,1043],{"class":1031}," authorize",[408,1045,1035],{"class":566},[408,1047,1048],{"class":1031}," sendEmail",[408,1050,1051],{"class":566}," },",[408,1053,1054],{"class":1031}," input",[408,1056,1057],{"class":566}," })",[408,1059,1060],{"class":555}," =>",[408,1062,567],{"class":566},[408,1064,1065],{"class":410,"line":417},[408,1066,573],{"class":572},[408,1068,1069,1072,1074,1076,1079,1081,1084,1086,1088,1091,1093,1095],{"class":410,"line":423},[408,1070,1071],{"class":551},"  await",[408,1073,1048],{"class":811},[408,1075,830],{"class":652},[408,1077,1078],{"class":687},"invite",[408,1080,798],{"class":566},[408,1082,1083],{"class":687},"email",[408,1085,1035],{"class":566},[408,1087,698],{"class":697},[408,1089,1090],{"class":701},"Invitation",[408,1092,705],{"class":697},[408,1094,1035],{"class":566},[408,1096,567],{"class":566},[408,1098,1099,1102,1104,1107,1109,1111],{"class":410,"line":429},[408,1100,1101],{"class":652},"    teamName",[408,1103,539],{"class":566},[408,1105,1106],{"class":687}," team",[408,1108,798],{"class":566},[408,1110,495],{"class":687},[408,1112,661],{"class":566},[408,1114,1115,1118,1120,1122,1124,1126],{"class":410,"line":435},[408,1116,1117],{"class":652},"    invitedBy",[408,1119,539],{"class":566},[408,1121,1032],{"class":687},[408,1123,798],{"class":566},[408,1125,495],{"class":687},[408,1127,661],{"class":566},[408,1129,1130,1133],{"class":410,"line":441},[408,1131,1132],{"class":687},"    inviteLink",[408,1134,661],{"class":566},[408,1136,1137,1140,1142],{"class":410,"line":447},[408,1138,1139],{"class":566},"  }",[408,1141,886],{"class":652},[408,1143,589],{"class":566},[408,1145,1146],{"class":410,"line":453},[408,1147,573],{"class":572},[408,1149,1150],{"class":410,"line":459},[408,1151,666],{"class":566},[317,1153,1154,1155,1158],{},"The emails Worker can also be invoked directly from any package via the ",[329,1156,1157],{},"sender"," helper:",[398,1160,1162],{"className":542,"code":1161,"language":544,"meta":404,"style":404},"import { sender } from \"@nuxfire\u002Ffunctions\u002Fsender\";\nconst sendEmail = sender(event.context?.cloudflare?.env?.Emails); \u002F\u002F pass the Emails binding\n",[329,1163,1164,1186],{"__ignoreMap":404},[408,1165,1166,1168,1170,1173,1175,1177,1179,1182,1184],{"class":410,"line":411},[408,1167,681],{"class":551},[408,1169,684],{"class":566},[408,1171,1172],{"class":687}," sender",[408,1174,691],{"class":566},[408,1176,694],{"class":551},[408,1178,698],{"class":697},[408,1180,1181],{"class":701},"@nuxfire\u002Ffunctions\u002Fsender",[408,1183,705],{"class":697},[408,1185,589],{"class":566},[408,1187,1188,1190,1192,1194,1196,1199,1201,1204,1207,1210,1212,1215,1217,1220,1223],{"class":410,"line":417},[408,1189,726],{"class":555},[408,1191,1048],{"class":559},[408,1193,641],{"class":563},[408,1195,1172],{"class":811},[408,1197,1198],{"class":687},"(event",[408,1200,798],{"class":566},[408,1202,1203],{"class":687},"context",[408,1205,1206],{"class":566},"?.",[408,1208,1209],{"class":687},"cloudflare",[408,1211,1206],{"class":566},[408,1213,1214],{"class":687},"env",[408,1216,1206],{"class":566},[408,1218,1219],{"class":687},"Emails)",[408,1221,1222],{"class":566},";",[408,1224,1225],{"class":572}," \u002F\u002F pass the Emails binding\n",[1227,1228,1229],"style",{},"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 .sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html.sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html pre.shiki code .sRxSC, html code.shiki .sRxSC{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit;--shiki-sepia:#F92672;--shiki-sepia-font-style:inherit}html pre.shiki code .srJo8, html code.shiki .srJo8{--shiki-light:#9C3EDA;--shiki-light-font-style:inherit;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit;--shiki-sepia:#66D9EF;--shiki-sepia-font-style:italic}html pre.shiki code .s91G_, html code.shiki .s91G_{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#F8F8F2}html pre.shiki code .sGXK2, html code.shiki .sGXK2{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583;--shiki-sepia:#F92672}html pre.shiki code .swvn1, html code.shiki .swvn1{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2}html pre.shiki code .ss7Ak, html code.shiki .ss7Ak{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit;--shiki-sepia:#88846F;--shiki-sepia-font-style:inherit}html pre.shiki code .sIDdj, html code.shiki .sIDdj{--shiki-light:#E53935;--shiki-default:#E36209;--shiki-dark:#FFAB70;--shiki-sepia:#F8F8F2}html pre.shiki code .s_MOj, html code.shiki .s_MOj{--shiki-light:#E2931D;--shiki-light-font-style:inherit;--shiki-default:#005CC5;--shiki-default-font-style:inherit;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit;--shiki-sepia:#66D9EF;--shiki-sepia-font-style:italic}html pre.shiki code .squCx, html code.shiki .squCx{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2}html pre.shiki code .s8HiA, html code.shiki .s8HiA{--shiki-light:#FF5370;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF}html pre.shiki code .ss--_, html code.shiki .ss--_{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2}html pre.shiki code .siCPE, html code.shiki .siCPE{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74}html pre.shiki code .sLACW, html code.shiki .sLACW{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74}html pre.shiki code .sKvfc, html code.shiki .sKvfc{--shiki-light:#E2931D;--shiki-light-text-decoration:inherit;--shiki-default:#6F42C1;--shiki-default-text-decoration:inherit;--shiki-dark:#B392F0;--shiki-dark-text-decoration:inherit;--shiki-sepia:#A6E22E;--shiki-sepia-text-decoration:underline}html pre.shiki code .sYThS, html code.shiki .sYThS{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF}html pre.shiki code .sD0ED, html code.shiki .sD0ED{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E}html pre.shiki code .sR7ES, html code.shiki .sR7ES{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E}html pre.shiki code .sTNss, html code.shiki .sTNss{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583;--shiki-sepia:#F92672}html pre.shiki code .sQgqH, html code.shiki .sQgqH{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit;--shiki-sepia:#FD971F;--shiki-sepia-font-style:italic}",{"title":404,"searchDepth":417,"depth":417,"links":1231},[1232,1233,1234,1235,1236],{"id":340,"depth":417,"text":341},{"id":389,"depth":417,"text":351},{"id":510,"depth":417,"text":511},{"id":946,"depth":417,"text":947},{"id":999,"depth":417,"text":1000},"Send emails with React Email and a provider-agnostic email worker. Switch between Resend, SES, Mailgun, SparkPost, or custom SMTP.","md",{},{"title":106,"description":1237},"aTKcOBFm5SI9f8fCWDDRJu90sOWfyP0oxdXLiVTCrRs",1790707485288]