[{"data":1,"prerenderedAt":20},["ShallowReactive",2],{"blog-ai-agents-send-email":3},{"slug":4,"title":5,"description":6,"date":7,"author":8,"image":12,"tags":13,"content":18,"readingTime":19},"ai-agents-send-email","How to let AI agents send email","Give your AI agents the ability to compose and send email programmatically using the Sendkit API.","2026-04-10",{"id":9,"name":10,"avatar":11},"paulo-castellano","Paulo Castellano","/images/authors/paulo.png","/images/blog/ai-agents-send-email/cover.jpg",[14,15,16,17],"ai","email-api","tutorial","automation","\u003Cp>AI agents that can&#39;t send email are half-built. They can reason, search, summarize, and plan — but the moment they need to notify a customer, follow up on a lead, or confirm an appointment, they hit a wall. Email is still the default communication channel for business, and your agents need direct access to it.\u003C/p>\n\u003Cp>This guide shows you how to wire up AI agents to send email through the \u003Ca href=\"/email-api\">Sendkit API\u003C/a>, with working code in Node.js and Python, safety guardrails, and webhook integration for closed-loop workflows.\u003C/p>\n\u003Ch2>Why AI agents need email\u003C/h2>\n\u003Cp>The use cases are everywhere once you look:\u003C/p>\n\u003Cul>\n\u003Cli>\u003Cstrong>Customer support agents\u003C/strong> resolve a ticket and send a summary to the customer. No human copies and pastes a template.\u003C/li>\n\u003Cli>\u003Cstrong>Sales agents\u003C/strong> qualify inbound leads and send personalized follow-ups within seconds of a form submission.\u003C/li>\n\u003Cli>\u003Cstrong>Scheduling agents\u003C/strong> negotiate meeting times over email, sending confirmations and calendar invites automatically.\u003C/li>\n\u003Cli>\u003Cstrong>Notification agents\u003C/strong> monitor systems and alert stakeholders when something breaks, with context the LLM assembled from logs.\u003C/li>\n\u003C/ul>\n\u003Cp>In each case, the agent generates the content. Your code validates it. Sendkit delivers it. That separation matters.\u003C/p>\n\u003Ch2>The architecture\u003C/h2>\n\u003Cp>Never let an LLM call an email API directly with no oversight. The pattern that works:\u003C/p>\n\u003Col>\n\u003Cli>\u003Cstrong>LLM generates content\u003C/strong> — subject line, body, recipient selection\u003C/li>\n\u003Cli>\u003Cstrong>Your code validates\u003C/strong> — checks recipient against allow-lists, scans content for policy violations, enforces rate limits\u003C/li>\n\u003Cli>\u003Cstrong>Sendkit sends\u003C/strong> — delivers the email and returns structured status\u003C/li>\n\u003C/ol>\n\u003Cp>This three-step flow keeps the agent useful without making it dangerous. The LLM never holds API credentials directly. Your application layer is the gatekeeper.\u003C/p>\n\u003Cp>\u003Cimg src=\"/images/blog/ai-agents-send-email/inline-1.jpg\" alt=\"Architecture for AI agent email sending\" width=\"1080\" height=\"720\" loading=\"lazy\" />\u003C/p>\n\u003Ch2>The tool/function calling pattern\u003C/h2>\n\u003Cp>Modern LLMs support tool calling (OpenAI calls them &quot;functions&quot;, Anthropic calls them &quot;tools&quot;). You define a \u003Ccode>send_email\u003C/code> tool with a schema, and the model invokes it when it decides an email should go out. Your code intercepts that call, validates it, and executes the actual send.\u003C/p>\n\u003Cp>Here&#39;s the tool definition you&#39;d give to an LLM:\u003C/p>\n\u003Cpre class=\"shiki dracula\" style=\"background-color:#282A36;color:#F8F8F2\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">{\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#8BE9FE\">  \"\u003C/span>\u003Cspan style=\"color:#8BE9FD\">name\u003C/span>\u003Cspan style=\"color:#8BE9FE\">\"\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#E9F284\"> \"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">send_email\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#8BE9FE\">  \"\u003C/span>\u003Cspan style=\"color:#8BE9FD\">description\u003C/span>\u003Cspan style=\"color:#8BE9FE\">\"\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#E9F284\"> \"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">Send an email to a recipient. Use this when the user needs to be notified via email or when a follow-up email is required.\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#8BE9FE\">  \"\u003C/span>\u003Cspan style=\"color:#8BE9FD\">parameters\u003C/span>\u003Cspan style=\"color:#8BE9FE\">\"\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#8BE9FE\">    \"\u003C/span>\u003Cspan style=\"color:#8BE9FD\">type\u003C/span>\u003Cspan style=\"color:#8BE9FE\">\"\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#E9F284\"> \"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">object\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#8BE9FE\">    \"\u003C/span>\u003Cspan style=\"color:#8BE9FD\">properties\u003C/span>\u003Cspan style=\"color:#8BE9FE\">\"\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#8BE9FE\">      \"\u003C/span>\u003Cspan style=\"color:#8BE9FD\">to\u003C/span>\u003Cspan style=\"color:#8BE9FE\">\"\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> { \u003C/span>\u003Cspan style=\"color:#8BE9FE\">\"\u003C/span>\u003Cspan style=\"color:#8BE9FD\">type\u003C/span>\u003Cspan style=\"color:#8BE9FE\">\"\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#E9F284\"> \"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">string\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\">, \u003C/span>\u003Cspan style=\"color:#8BE9FE\">\"\u003C/span>\u003Cspan style=\"color:#8BE9FD\">description\u003C/span>\u003Cspan style=\"color:#8BE9FE\">\"\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#E9F284\"> \"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">Recipient email address\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> },\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#8BE9FE\">      \"\u003C/span>\u003Cspan style=\"color:#8BE9FD\">subject\u003C/span>\u003Cspan style=\"color:#8BE9FE\">\"\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> { \u003C/span>\u003Cspan style=\"color:#8BE9FE\">\"\u003C/span>\u003Cspan style=\"color:#8BE9FD\">type\u003C/span>\u003Cspan style=\"color:#8BE9FE\">\"\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#E9F284\"> \"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">string\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\">, \u003C/span>\u003Cspan style=\"color:#8BE9FE\">\"\u003C/span>\u003Cspan style=\"color:#8BE9FD\">description\u003C/span>\u003Cspan style=\"color:#8BE9FE\">\"\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#E9F284\"> \"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">Email subject line\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> },\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#8BE9FE\">      \"\u003C/span>\u003Cspan style=\"color:#8BE9FD\">html\u003C/span>\u003Cspan style=\"color:#8BE9FE\">\"\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> { \u003C/span>\u003Cspan style=\"color:#8BE9FE\">\"\u003C/span>\u003Cspan style=\"color:#8BE9FD\">type\u003C/span>\u003Cspan style=\"color:#8BE9FE\">\"\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#E9F284\"> \"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">string\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\">, \u003C/span>\u003Cspan style=\"color:#8BE9FE\">\"\u003C/span>\u003Cspan style=\"color:#8BE9FD\">description\u003C/span>\u003Cspan style=\"color:#8BE9FE\">\"\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#E9F284\"> \"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">Email body as HTML\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">    },\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#8BE9FE\">    \"\u003C/span>\u003Cspan style=\"color:#8BE9FD\">required\u003C/span>\u003Cspan style=\"color:#8BE9FE\">\"\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> [\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">to\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\">, \u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">subject\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\">, \u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">html\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\">]\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">  }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">}\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\u003Cp>The LLM never sees your API key. It just fills in \u003Ccode>to\u003C/code>, \u003Ccode>subject\u003C/code>, and \u003Ccode>html\u003C/code>. Your code handles the rest.\u003C/p>\n\u003Ch2>Node.js: agent tool that sends email via Sendkit\u003C/h2>\n\u003Cp>Install the SDK:\u003C/p>\n\u003Cpre class=\"shiki dracula\" style=\"background-color:#282A36;color:#F8F8F2\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#50FA7B\">npm\u003C/span>\u003Cspan style=\"color:#F1FA8C\"> install\u003C/span>\u003Cspan style=\"color:#F1FA8C\"> @sendkitdev/sdk\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\u003Cp>Define the tool handler:\u003C/p>\n\u003Cpre class=\"shiki dracula\" style=\"background-color:#282A36;color:#F8F8F2\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">import\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> { Sendkit } \u003C/span>\u003Cspan style=\"color:#FF79C6\">from\u003C/span>\u003Cspan style=\"color:#E9F284\"> '\u003C/span>\u003Cspan style=\"color:#F1FA8C\">@sendkitdev/sdk\u003C/span>\u003Cspan style=\"color:#E9F284\">'\u003C/span>\u003Cspan style=\"color:#F8F8F2\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">const\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> sendkit \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#FF79C6;font-weight:bold\"> new\u003C/span>\u003Cspan style=\"color:#50FA7B\"> Sendkit\u003C/span>\u003Cspan style=\"color:#F8F8F2\">(\u003C/span>\u003Cspan style=\"color:#E9F284\">'\u003C/span>\u003Cspan style=\"color:#F1FA8C\">sk_live_your_api_key\u003C/span>\u003Cspan style=\"color:#E9F284\">'\u003C/span>\u003Cspan style=\"color:#F8F8F2\">);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">const\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> APPROVED_SENDERS \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> [\u003C/span>\u003Cspan style=\"color:#E9F284\">'\u003C/span>\u003Cspan style=\"color:#F1FA8C\">support@yourapp.com\u003C/span>\u003Cspan style=\"color:#E9F284\">'\u003C/span>\u003Cspan style=\"color:#F8F8F2\">, \u003C/span>\u003Cspan style=\"color:#E9F284\">'\u003C/span>\u003Cspan style=\"color:#F1FA8C\">sales@yourapp.com\u003C/span>\u003Cspan style=\"color:#E9F284\">'\u003C/span>\u003Cspan style=\"color:#F8F8F2\">];\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">const\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> RATE_LIMIT \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#FF79C6;font-weight:bold\"> new\u003C/span>\u003Cspan style=\"color:#50FA7B\"> Map\u003C/span>\u003Cspan style=\"color:#F8F8F2\">(); \u003C/span>\u003Cspan style=\"color:#6272A4\">// email -> timestamp[]\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">const\u003C/span>\u003Cspan style=\"color:#50FA7B\"> handleSendEmailTool\u003C/span>\u003Cspan style=\"color:#FF79C6\"> =\u003C/span>\u003Cspan style=\"color:#FF79C6\"> async\u003C/span>\u003Cspan style=\"color:#FFB86C;font-style:italic\"> params\u003C/span>\u003Cspan style=\"color:#FF79C6\"> =>\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">  const\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> { to, subject, html } \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> params;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">  const\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> from \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#E9F284\"> '\u003C/span>\u003Cspan style=\"color:#F1FA8C\">support@yourapp.com\u003C/span>\u003Cspan style=\"color:#E9F284\">'\u003C/span>\u003Cspan style=\"color:#F8F8F2\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6272A4\">  // Validate sender\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">  if\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> (\u003C/span>\u003Cspan style=\"color:#FF79C6\">!\u003C/span>\u003Cspan style=\"color:#BD93F9\">APPROVED_SENDERS\u003C/span>\u003Cspan style=\"color:#F8F8F2\">.\u003C/span>\u003Cspan style=\"color:#50FA7B\">includes\u003C/span>\u003Cspan style=\"color:#F8F8F2\">(from)) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">    return\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> { error\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#E9F284\"> '\u003C/span>\u003Cspan style=\"color:#F1FA8C\">Sender not in approved list\u003C/span>\u003Cspan style=\"color:#E9F284\">'\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> };\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">  }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6272A4\">  // Rate limit: max 5 emails per recipient per hour\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">  const\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> now \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> Date.\u003C/span>\u003Cspan style=\"color:#50FA7B\">now\u003C/span>\u003Cspan style=\"color:#F8F8F2\">();\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">  const\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> history \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#BD93F9\"> RATE_LIMIT\u003C/span>\u003Cspan style=\"color:#F8F8F2\">.\u003C/span>\u003Cspan style=\"color:#50FA7B\">get\u003C/span>\u003Cspan style=\"color:#F8F8F2\">(to) \u003C/span>\u003Cspan style=\"color:#FF79C6\">||\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> [];\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">  const\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> recent \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> history.\u003C/span>\u003Cspan style=\"color:#50FA7B\">filter\u003C/span>\u003Cspan style=\"color:#F8F8F2\">(\u003C/span>\u003Cspan style=\"color:#FFB86C;font-style:italic\">ts\u003C/span>\u003Cspan style=\"color:#FF79C6\"> =>\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> now \u003C/span>\u003Cspan style=\"color:#FF79C6\">-\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> ts \u003C/span>\u003Cspan style=\"color:#FF79C6\">&#x3C;\u003C/span>\u003Cspan style=\"color:#BD93F9\"> 3600000\u003C/span>\u003Cspan style=\"color:#F8F8F2\">);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">  if\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> (recent.length \u003C/span>\u003Cspan style=\"color:#FF79C6\">>=\u003C/span>\u003Cspan style=\"color:#BD93F9\"> 5\u003C/span>\u003Cspan style=\"color:#F8F8F2\">) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">    return\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> { error\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#E9F284\"> '\u003C/span>\u003Cspan style=\"color:#F1FA8C\">Rate limit exceeded for this recipient\u003C/span>\u003Cspan style=\"color:#E9F284\">'\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> };\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">  }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6272A4\">  // Send via Sendkit\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">  const\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> { data, error } \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#FF79C6\"> await\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> sendkit.emails.\u003C/span>\u003Cspan style=\"color:#50FA7B\">send\u003C/span>\u003Cspan style=\"color:#F8F8F2\">({\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">    from,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">    to,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">    subject,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">    html,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">  });\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">  if\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> (error) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">    return\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> { error\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> error.message };\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">  }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6272A4\">  // Track for rate limiting\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">  recent.\u003C/span>\u003Cspan style=\"color:#50FA7B\">push\u003C/span>\u003Cspan style=\"color:#F8F8F2\">(now);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BD93F9\">  RATE_LIMIT\u003C/span>\u003Cspan style=\"color:#F8F8F2\">.\u003C/span>\u003Cspan style=\"color:#50FA7B\">set\u003C/span>\u003Cspan style=\"color:#F8F8F2\">(to, recent);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">  return\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> { success\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#BD93F9\"> true\u003C/span>\u003Cspan style=\"color:#F8F8F2\">, messageId\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> data.id };\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">};\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\u003Cp>Wire this into your LLM loop. When the model returns a tool call with \u003Ccode>name: &quot;send_email&quot;\u003C/code>, parse the arguments and pass them to \u003Ccode>handleSendEmailTool\u003C/code>. Return the result back to the model so it can confirm delivery to the user.\u003C/p>\n\u003Cp>For a deeper dive on Node.js email sending, see \u003Ca href=\"/blog/send-transactional-email-nodejs\">How to send transactional email with Node.js\u003C/a>.\u003C/p>\n\u003Ch2>Python: agent tool that sends email via Sendkit\u003C/h2>\n\u003Cp>Install the SDK:\u003C/p>\n\u003Cpre class=\"shiki dracula\" style=\"background-color:#282A36;color:#F8F8F2\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#50FA7B\">pip\u003C/span>\u003Cspan style=\"color:#F1FA8C\"> install\u003C/span>\u003Cspan style=\"color:#F1FA8C\"> sendkit\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\u003Cp>Define the tool handler:\u003C/p>\n\u003Cpre class=\"shiki dracula\" style=\"background-color:#282A36;color:#F8F8F2\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">from\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> sendkit \u003C/span>\u003Cspan style=\"color:#FF79C6\">import\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> Sendkit\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">from\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> time \u003C/span>\u003Cspan style=\"color:#FF79C6\">import\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> time\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">client \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> Sendkit(\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">sk_live_your_api_key\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\">)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BD93F9\">APPROVED_SENDERS\u003C/span>\u003Cspan style=\"color:#FF79C6\"> =\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> [\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">support@yourapp.com\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\">, \u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">sales@yourapp.com\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\">]\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">rate_limit: dict[\u003C/span>\u003Cspan style=\"color:#8BE9FD;font-style:italic\">str\u003C/span>\u003Cspan style=\"color:#F8F8F2\">, list[\u003C/span>\u003Cspan style=\"color:#8BE9FD;font-style:italic\">float\u003C/span>\u003Cspan style=\"color:#F8F8F2\">]] \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> {}\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">def\u003C/span>\u003Cspan style=\"color:#50FA7B\"> handle_send_email_tool\u003C/span>\u003Cspan style=\"color:#F8F8F2\">(\u003C/span>\u003Cspan style=\"color:#FFB86C;font-style:italic\">params\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#8BE9FD;font-style:italic\"> dict\u003C/span>\u003Cspan style=\"color:#F8F8F2\">) \u003C/span>\u003Cspan style=\"color:#FF79C6\">->\u003C/span>\u003Cspan style=\"color:#8BE9FD;font-style:italic\"> dict\u003C/span>\u003Cspan style=\"color:#F8F8F2\">:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">    to \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> params[\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">to\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\">]\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">    subject \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> params[\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">subject\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\">]\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">    html \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> params[\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">html\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\">]\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">    from_ \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#E9F284\"> \"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">support@yourapp.com\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">    if\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> from_ \u003C/span>\u003Cspan style=\"color:#FF79C6\">not\u003C/span>\u003Cspan style=\"color:#FF79C6\"> in\u003C/span>\u003Cspan style=\"color:#BD93F9\"> APPROVED_SENDERS\u003C/span>\u003Cspan style=\"color:#F8F8F2\">:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">        return\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> {\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">error\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\">: \u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">Sender not in approved list\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\">}\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6272A4\">    # Rate limit: max 5 emails per recipient per hour\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">    now \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> time()\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">    history \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> rate_limit.get(to, [])\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">    recent \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> [ts \u003C/span>\u003Cspan style=\"color:#FF79C6\">for\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> ts \u003C/span>\u003Cspan style=\"color:#FF79C6\">in\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> history \u003C/span>\u003Cspan style=\"color:#FF79C6\">if\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> now \u003C/span>\u003Cspan style=\"color:#FF79C6\">-\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> ts \u003C/span>\u003Cspan style=\"color:#FF79C6\">&#x3C;\u003C/span>\u003Cspan style=\"color:#BD93F9\"> 3600\u003C/span>\u003Cspan style=\"color:#F8F8F2\">]\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">    if\u003C/span>\u003Cspan style=\"color:#8BE9FD\"> len\u003C/span>\u003Cspan style=\"color:#F8F8F2\">(recent) \u003C/span>\u003Cspan style=\"color:#FF79C6\">>=\u003C/span>\u003Cspan style=\"color:#BD93F9\"> 5\u003C/span>\u003Cspan style=\"color:#F8F8F2\">:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">        return\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> {\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">error\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\">: \u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">Rate limit exceeded for this recipient\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\">}\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">    result \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> client.emails.send(\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFB86C;font-style:italic\">        from_\u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#F8F8F2\">from_,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFB86C;font-style:italic\">        to\u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#F8F8F2\">to,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFB86C;font-style:italic\">        subject\u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#F8F8F2\">subject,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFB86C;font-style:italic\">        html\u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#F8F8F2\">html,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">    )\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">    if\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> result.error:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">        return\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> {\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">error\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\">: result.error.message}\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">    recent.append(now)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">    rate_limit[to] \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> recent\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">    return\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> {\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">success\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\">: \u003C/span>\u003Cspan style=\"color:#BD93F9\">True\u003C/span>\u003Cspan style=\"color:#F8F8F2\">, \u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F1FA8C\">message_id\u003C/span>\u003Cspan style=\"color:#E9F284\">\"\u003C/span>\u003Cspan style=\"color:#F8F8F2\">: result.data.id}\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\u003Cp>For more on Python email sending, see \u003Ca href=\"/blog/send-email-python\">How to send email with Python\u003C/a>.\u003C/p>\n\u003Ch2>Validate recipients before sending\u003C/h2>\n\u003Cp>An AI agent that sends to invalid addresses burns your sender reputation. Before every send, validate the recipient using \u003Ca href=\"/email-validations\">Sendkit&#39;s email validation API\u003C/a>:\u003C/p>\n\u003Cpre class=\"shiki dracula\" style=\"background-color:#282A36;color:#F8F8F2\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">const\u003C/span>\u003Cspan style=\"color:#50FA7B\"> validateAndSend\u003C/span>\u003Cspan style=\"color:#FF79C6\"> =\u003C/span>\u003Cspan style=\"color:#FF79C6\"> async\u003C/span>\u003Cspan style=\"color:#FFB86C;font-style:italic\"> params\u003C/span>\u003Cspan style=\"color:#FF79C6\"> =>\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">  const\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> { to, subject, html } \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> params;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6272A4\">  // Validate recipient first\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">  const\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> { data\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> validation } \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#FF79C6\"> await\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> sendkit.emailValidations.\u003C/span>\u003Cspan style=\"color:#50FA7B\">validate\u003C/span>\u003Cspan style=\"color:#F8F8F2\">({\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">    email\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> to,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">  });\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">  if\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> (validation.result \u003C/span>\u003Cspan style=\"color:#FF79C6\">===\u003C/span>\u003Cspan style=\"color:#E9F284\"> '\u003C/span>\u003Cspan style=\"color:#F1FA8C\">undeliverable\u003C/span>\u003Cspan style=\"color:#E9F284\">'\u003C/span>\u003Cspan style=\"color:#F8F8F2\">) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">    return\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> { error\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#F1FA8C\"> `Invalid recipient: \u003C/span>\u003Cspan style=\"color:#FF79C6\">${\u003C/span>\u003Cspan style=\"color:#F8F8F2\">to\u003C/span>\u003Cspan style=\"color:#FF79C6\">}\u003C/span>\u003Cspan style=\"color:#F1FA8C\">`\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> };\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">  }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">  if\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> (validation.is_disposable) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">    return\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> { error\u003C/span>\u003Cspan style=\"color:#FF79C6\">:\u003C/span>\u003Cspan style=\"color:#E9F284\"> '\u003C/span>\u003Cspan style=\"color:#F1FA8C\">Disposable email addresses are not allowed\u003C/span>\u003Cspan style=\"color:#E9F284\">'\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> };\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">  }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6272A4\">  // Proceed with send\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">  return\u003C/span>\u003Cspan style=\"color:#50FA7B\"> handleSendEmailTool\u003C/span>\u003Cspan style=\"color:#F8F8F2\">(params);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">};\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\u003Cp>This catches typos, dead mailboxes, and disposable addresses before they hit your sending infrastructure. Your bounce rate stays low, and your domain reputation stays intact. Read more about this in \u003Ca href=\"/blog/handle-email-bounces\">How to handle email bounces\u003C/a>.\u003C/p>\n\u003Cp>\u003Cimg src=\"/images/blog/ai-agents-send-email/inline-2.jpg\" alt=\"Monitoring email delivery and agent activity\" width=\"1080\" height=\"720\" loading=\"lazy\" />\u003C/p>\n\u003Ch2>Safety guardrails\u003C/h2>\n\u003Cp>Giving an LLM the ability to send email on your behalf requires serious guardrails. Here&#39;s what to implement:\u003C/p>\n\u003Cp>\u003Cstrong>Approved sender and recipient lists.\u003C/strong> Restrict the \u003Ccode>from\u003C/code> address to verified senders. For high-risk agents, maintain an allow-list of recipient domains too.\u003C/p>\n\u003Cp>\u003Cstrong>Rate limiting.\u003C/strong> Both per-recipient and global. An agent stuck in a loop can spam a mailbox in seconds. The code examples above show per-recipient limits — add a global counter as well.\u003C/p>\n\u003Cp>\u003Cstrong>Content review.\u003C/strong> Scan outgoing messages for sensitive data (SSNs, credit card numbers, internal URLs). A regex pass catches the obvious cases. For stricter environments, run a second LLM call to audit the content.\u003C/p>\n\u003Cp>\u003Cstrong>Human-in-the-loop.\u003C/strong> For sensitive emails — legal notices, financial disclosures, anything to a VIP list — queue the email for human approval instead of sending immediately. The agent drafts, a human approves, then your code sends.\u003C/p>\n\u003Cp>\u003Cstrong>Logging.\u003C/strong> Log every email the agent sends, including the full prompt context that led to the send. You need an audit trail.\u003C/p>\n\u003Ch2>Webhook integration\u003C/h2>\n\u003Cp>Sending is half the loop. Your agent also needs to react to what happens after delivery. Sendkit fires webhooks for delivery events, bounces, opens, clicks, and complaints.\u003C/p>\n\u003Cpre class=\"shiki dracula\" style=\"background-color:#282A36;color:#F8F8F2\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">import\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> express \u003C/span>\u003Cspan style=\"color:#FF79C6\">from\u003C/span>\u003Cspan style=\"color:#E9F284\"> '\u003C/span>\u003Cspan style=\"color:#F1FA8C\">express\u003C/span>\u003Cspan style=\"color:#E9F284\">'\u003C/span>\u003Cspan style=\"color:#F8F8F2\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">const\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> app \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#50FA7B\"> express\u003C/span>\u003Cspan style=\"color:#F8F8F2\">();\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">app.\u003C/span>\u003Cspan style=\"color:#50FA7B\">use\u003C/span>\u003Cspan style=\"color:#F8F8F2\">(express.\u003C/span>\u003Cspan style=\"color:#50FA7B\">json\u003C/span>\u003Cspan style=\"color:#F8F8F2\">());\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">app.\u003C/span>\u003Cspan style=\"color:#50FA7B\">post\u003C/span>\u003Cspan style=\"color:#F8F8F2\">(\u003C/span>\u003Cspan style=\"color:#E9F284\">'\u003C/span>\u003Cspan style=\"color:#F1FA8C\">/webhooks/sendkit\u003C/span>\u003Cspan style=\"color:#E9F284\">'\u003C/span>\u003Cspan style=\"color:#F8F8F2\">, (\u003C/span>\u003Cspan style=\"color:#FFB86C;font-style:italic\">req\u003C/span>\u003Cspan style=\"color:#F8F8F2\">, \u003C/span>\u003Cspan style=\"color:#FFB86C;font-style:italic\">res\u003C/span>\u003Cspan style=\"color:#F8F8F2\">) \u003C/span>\u003Cspan style=\"color:#FF79C6\">=>\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">  const\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> event \u003C/span>\u003Cspan style=\"color:#FF79C6\">=\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> req.body;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">  switch\u003C/span>\u003Cspan style=\"color:#F8F8F2\"> (event.type) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">    case\u003C/span>\u003Cspan style=\"color:#E9F284\"> '\u003C/span>\u003Cspan style=\"color:#F1FA8C\">email.bounced\u003C/span>\u003Cspan style=\"color:#E9F284\">'\u003C/span>\u003Cspan style=\"color:#F8F8F2\">:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6272A4\">      // Feed back to agent: this recipient is invalid\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6272A4\">      // Update your allow-list or CRM\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">      break\u003C/span>\u003Cspan style=\"color:#F8F8F2\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">    case\u003C/span>\u003Cspan style=\"color:#E9F284\"> '\u003C/span>\u003Cspan style=\"color:#F1FA8C\">email.delivered\u003C/span>\u003Cspan style=\"color:#E9F284\">'\u003C/span>\u003Cspan style=\"color:#F8F8F2\">:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6272A4\">      // Mark conversation as \"email sent successfully\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">      break\u003C/span>\u003Cspan style=\"color:#F8F8F2\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">    case\u003C/span>\u003Cspan style=\"color:#E9F284\"> '\u003C/span>\u003Cspan style=\"color:#F1FA8C\">email.complained\u003C/span>\u003Cspan style=\"color:#E9F284\">'\u003C/span>\u003Cspan style=\"color:#F8F8F2\">:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6272A4\">      // Block future sends to this recipient\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6272A4\">      // Alert your team\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF79C6\">      break\u003C/span>\u003Cspan style=\"color:#F8F8F2\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">  }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">  res.\u003C/span>\u003Cspan style=\"color:#50FA7B\">sendStatus\u003C/span>\u003Cspan style=\"color:#F8F8F2\">(\u003C/span>\u003Cspan style=\"color:#BD93F9\">200\u003C/span>\u003Cspan style=\"color:#F8F8F2\">);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F8F8F2\">});\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\u003Cp>Wire bounce events back into your agent&#39;s context. If a recipient bounces, the agent should know not to retry that address. This creates a feedback loop that makes the agent smarter over time.\u003C/p>\n\u003Ch2>Why API beats SMTP for agents\u003C/h2>\n\u003Cp>SMTP is a conversation protocol. Your code opens a socket, negotiates TLS, authenticates, sends MAIL FROM, RCPT TO, DATA, waits for response codes. It&#39;s fragile, slow, and gives you almost no structured feedback.\u003C/p>\n\u003Cp>An API call is a single HTTP request. You get back JSON with a message ID, or a structured error with a code you can branch on. For an AI agent that might send dozens of emails in a session, the difference is massive:\u003C/p>\n\u003Cul>\n\u003Cli>\u003Cstrong>Speed\u003C/strong> — one HTTP round-trip vs. a multi-step SMTP handshake\u003C/li>\n\u003Cli>\u003Cstrong>Error handling\u003C/strong> — typed error objects vs. parsing SMTP reply codes\u003C/li>\n\u003Cli>\u003Cstrong>Observability\u003C/strong> — every send is logged with metadata, queryable via the API\u003C/li>\n\u003Cli>\u003Cstrong>No connection management\u003C/strong> — no persistent sockets, no pooling, no timeout drama\u003C/li>\n\u003C/ul>\n\u003Cp>If you want a detailed comparison, read \u003Ca href=\"/blog/smtp-vs-email-api\">SMTP vs Email API\u003C/a>.\u003C/p>\n\u003Ch2>Putting it all together\u003C/h2>\n\u003Cp>The stack is straightforward: your LLM generates email content through tool calling, your application layer validates and rate-limits, Sendkit handles delivery and gives you structured feedback through webhooks. The agent stays useful without being dangerous.\u003C/p>\n\u003Cp>Start with the \u003Ca href=\"https://docs.sendkit.dev/api-reference/introduction\">Sendkit API reference\u003C/a> to get your keys and verify a domain. Check \u003Ca href=\"/pricing\">pricing\u003C/a> — the free tier is generous enough to build and test your agent before you scale.\u003C/p>\n\u003Cp>The agents that win are the ones that can actually do things. Sending email is one of the most valuable actions you can unlock.\u003C/p>\n",8,1775845586560]