1import{j as e}from"./DJx4IWN9.js";const t={title:"Send emails with FastAPI"};function s(r){const n={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",...r.components};return e.jsxs(e.Fragment,{children:[e.jsx(n.h1,{children:"Send emails with FastAPI"}),` 2`,e.jsxs(n.p,{children:["In this quickstart, you'll learn how to send transactional emails from your ",e.jsx(n.a,{href:"https://fastapi.tiangolo.com/",children:"FastAPI"})," app with Sidemail. You'll set up the SDK, send your first email, and see examples for common use cases like welcome emails, password resets, and background tasks."]}),` 3`,e.jsx(n.h2,{children:"Before you start"}),` 4`,e.jsxs(n.ol,{children:[` 5`,e.jsxs(n.li,{children:[e.jsx(n.a,{href:"https://sidemail.io",children:"Create a Sidemail account"})," â get your API key"]}),` 6`,e.jsxs(n.li,{children:[e.jsx(n.a,{href:"/docs/sending-identities/",children:"Add a sending domain"})," â set up your domain for sending"]}),` 7`]}),` 8`,e.jsx(n.h2,{children:"1. Install"}),` 9`,e.jsx(n.pre,{children:e.jsx(n.code,{className:"language-bash",children:`pip install sidemail 10`})}),` 11`,e.jsx(n.h2,{children:"2. Configure API key"}),` 12`,e.jsxs(n.p,{children:["Add your Sidemail API key to ",e.jsx(n.code,{children:".env"}),":"]}),` 13`,e.jsx(n.pre,{children:e.jsx(n.code,{className:"language-bash",children:`SIDEMAIL_API_KEY=your-api-key 14`})}),` 15`,e.jsx(n.h2,{children:"3. Setup client"}),` 16`,e.jsx(n.p,{children:"Create a shared instance of the Sidemail client."}),` 17`,e.jsx(n.pre,{children:e.jsx(n.code,{className:"language-python",children:`# services.py\r 18from sidemail import Sidemail\r 19import os\r 20\r 21# The SDK automatically reads SIDEMAIL_API_KEY from environment variables\r 22sidemail = Sidemail() 23`})}),` 24`,e.jsx(n.h2,{children:"4. Send a welcome email"}),` 25`,e.jsxs(n.p,{children:["Send an email when a user registers. We use a standard ",e.jsx(n.code,{children:"def"})," route so FastAPI runs the synchronous Sidemail SDK in a threadpool, preventing it from blocking the event loop."]}),` 26`,e.jsx(n.pre,{children:e.jsx(n.code,{className:"language-python",children:`# main.py\r 27from fastapi import FastAPI\r 28from pydantic import BaseModel\r 29from .services import sidemail\r 30\r 31app = FastAPI()\r 32\r 33class User(BaseModel):\r 34 email: str\r 35 name: str\r 36\r 37@app.post("/register")\r 38def register(user: User):\r 39 # ... create user in database ...\r 40\r 41 sidemail.send_email(\r 42 toAddress=user.email,\r 43 fromAddress="[email protected]",\r 44 fromName="Your App",\r 45 templateName="Welcome",\r 46 templateProps={"firstName": user.name},\r 47 )\r 48\r 49 return {"message": "User registered"} 50`})}),` 51`,e.jsx(n.h2,{children:"5. Send a password reset email"}),` 52`,e.jsx(n.pre,{children:e.jsx(n.code,{className:"language-python",children:`# main.py\r 53class PasswordResetRequest(BaseModel):\r 54 email: str\r 55\r 56@app.post("/forgot-password")\r 57def forgot_password(request: PasswordResetRequest):\r 58 token = "secure-reset-token" # Generate this securely\r 59\r 60 sidemail.send_email(\r 61 toAddress=request.email,\r 62 fromAddress="[email protected]",\r 63 fromName="Your App",\r 64 templateName="Password Reset",\r 65 templateProps={\r 66 "actionUrl": f"https://myapp.com/reset/{token}",\r 67 },\r 68 )\r 69\r 70 return {"message": "Reset email sent"} 71`})}),` 72`,e.jsx(n.h2,{children:"6. Send a weekly report"}),` 73`,e.jsx(n.p,{children:"You can create a standalone script for cron jobs."}),` 74`,e.jsx(n.pre,{children:e.jsx(n.code,{className:"language-python",children:`# scripts/send_weekly_report.py\r 75from myapp.services import sidemail\r 76\r 77def main():\r 78 # In a real app, fetch this from your database\r 79 new_signups = 150\r 80 chart_data = [100, 200, 300, 400, 200, 300, 200, 500]\r 81\r 82 sidemail.send_email(\r 83 toAddress="[email protected]",\r 84 fromAddress="[email protected]",\r 85 fromName="My App",\r 86 templateName="Weekly Report",\r 87 templateProps={\r 88 "signups": new_signups,\r 89 "chart": chart_data,\r 90 },\r 91 )\r 92 print("Weekly report sent")\r 93\r 94if __name__ == "__main__":\r 95 main() 96`})}),` 97`,e.jsx(n.p,{children:"Run it via cron:"}),`
98`,e.jsx(n.pre,{children:e.jsx(n.code,{className:"language-bash",children:`# Run every Monday at 8:00 AM\r 990 8 * * 1 python -m scripts.send_weekly_report 100`})}),` 101`,e.jsx(n.h2,{children:"7. Send email via Background Tasks"}),` 102`,e.jsxs(n.p,{children:["Decouple email sending from the response using FastAPI's ",e.jsx(n.code,{children:"BackgroundTasks"}),". This allows you to return a response immediately while the email sends in the background."]}),` 103`,e.jsx(n.pre,{children:e.jsx(n.code,{className:"language-python",children:`# main.py\r 104from fastapi import BackgroundTasks\r 105\r 106def send_welcome_email_task(email: str, name: str):\r 107 sidemail.send_email(\r 108 toAddress=email,\r 109 fromAddress="[email protected]",\r 110 fromName="My App",\r 111 templateName="Welcome",\r 112 templateProps={"firstName": name},\r 113 )\r 114\r 115@app.post("/register-async")\r 116async def register_async(user: User, background_tasks: BackgroundTasks):\r 117 # ... create user in database ...\r 118\r 119 background_tasks.add_task(send_welcome_email_task, user.email, user.name)\r 120\r 121 return {"message": "User registered, email sending in background"} 122`})}),` 123`,e.jsx(n.h2,{children:"8. Send HTML email"}),` 124`,e.jsxs(n.p,{children:["Use ",e.jsx(n.code,{children:"jinja2"})," to generate HTML from templates."]}),` 125`,e.jsx(n.pre,{children:e.jsx(n.code,{className:"language-python",children:`from fastapi.templating import Jinja2Templates\r 126\r 127templates = Jinja2Templates(directory="templates")\r 128\r 129@app.post("/send-invoice")\r 130def send_invoice(email: str):\r 131 # templates/invoice.html\r 132 template = templates.get_template("invoice.html")\r 133 html_content = template.render(amount=99)\r 134\r 135 sidemail.send_email(\r 136 toAddress=email,\r 137 fromAddress="[email protected]",\r 138 fromName="Your App",\r 139 subject="Your Invoice",\r 140 html=html_content,\r 141 )\r 142\r 143 return {"message": "Invoice sent"} 144`})}),` 145`,e.jsx(n.h2,{children:"9. Send Markdown email"}),` 146`,e.jsxs(n.p,{children:["Store your markdown content in a file and load it (",e.jsx(n.a,{href:"https://sidemail.io/docs/markdown-emails/",children:"learn more"}),")."]}),` 147`,e.jsx(n.pre,{children:e.jsx(n.code,{className:"language-python",children:`def send_markdown():\r 148 with open("templates/emails/welcome.md", "r") as f:\r 149 markdown_content = f.read()\r 150\r 151 # Subject and sender are defined in the markdown frontmatter\r 152 sidemail.send_email(\r 153 toAddress="[email protected]",\r 154 markdown=markdown_content,\r 155 templateProps={\r 156 "name": "John",\r 157 "link": "https://example.com",\r 158 },\r 159 ) 160`})}),` 161`,e.jsx(n.h2,{children:"10. Send plain text email"}),` 162`,e.jsx(n.pre,{children:e.jsx(n.code,{className:"language-python",children:`sidemail.send_email(\r 163 toAddress="[email protected]",\r 164 fromAddress="[email protected]",\r 165 fromName="Your App",\r 166 subject="Hello",\r 167 text="Hello! ð",\r 168) 169`})}),` 170`,e.jsx(n.h2,{children:"11. Schedule email"}),` 171`,e.jsxs(n.p,{children:["Send email later. Set ",e.jsx(n.code,{children:"scheduledAt"})," to an ISO date string in the future, no more than 30 days from now."]}),` 172`,e.jsx(n.pre,{children:e.jsx(n.code,{className:"language-python",children:`import datetime\r 173\r 174# Schedule for 1 hour from now\r 175scheduled_at = (datetime.datetime.utcnow() + datetime.timedelta(hours=1)).isoformat() + "Z"\r 176\r 177sidemail.send_email(\r 178 toAddress="[email protected]",\r 179 fromAddress="[email protected]",\r 180 fromName="Your App",\r 181 templateName="Welcome",\r 182 templateProps={"firstName": "Alex"},\r 183 scheduledAt=scheduled_at,\r 184) 185`})}),` 186`,e.jsx(n.h2,{children:"12. Send with attachment"}),` 187`,e.jsxs(n.p,{children:["Use the ",e.jsx(n.code,{children:"Sidemail.file_to_attachment"})," helper to attach files."]}),` 188`,e.jsx(n.pre,{children:e.jsx(n.code,{className:"language-python",children:`from sidemail import Sidemail\r 189\r 190with open("invoice.pdf", "rb") as f:\r 191 pdf_data = f.read()\r 192\r 193attachment = Sidemail.file_to_attachment("invoice.pdf", pdf_data)\r 194\r 195sidemail.send_email(\r 196 toAddress="[email protected]",\r 197 fromAddress="[email protected]",\r 198 fromName="Your App",\r 199 subject="Your invoice",\r 200 text="See attached.",\r 201 attachments=[attachment],\r 202) 203`})}),` 204`,e.jsx(n.h2,{children:"13. Handle errors"}),`
205`,e.jsx(n.pre,{children:e.jsx(n.code,{className:"language-python",children:`from sidemail import SidemailError\r 206import logging\r 207\r 208logger = logging.getLogger(__name__)\r 209\r 210try:\r 211 sidemail.send_email(\r 212 # ...\r 213 )\r 214except SidemailError as e:\r 215 logger.error(f"Sidemail error: {e.message}") 216`})})]})}function i(r={}){const{wrapper:n}=r.components||{};return n?e.jsx(n,{...r,children:e.jsx(s,{...r})}):s(r)}export{i as default,t as meta};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.