package mainimport ( "context" "fmt" "log" "os" "github.com/AhaSend/ahasend-go" "github.com/AhaSend/ahasend-go/api" "github.com/AhaSend/ahasend-go/models/common" "github.com/AhaSend/ahasend-go/models/requests" "github.com/google/uuid")func main() { client := api.NewAPIClient(api.WithAPIKey(os.Getenv("AHASEND_API_KEY"))) accountID := uuid.MustParse(os.Getenv("AHASEND_ACCOUNT_ID")) ctx := context.Background() // The SDK sends a fresh Idempotency-Key with every POST and reuses it on its // own retries. Deriving the key from your own ID instead also makes a rerun // of the same job (after a crash, say) return the first send, not a second. orderID := "1234" response, _, err := client.MessagesAPI.CreateMessage(ctx, accountID, requests.CreateMessageRequest{ From: common.SenderAddress{ Email: "info@example.com", Name: ahasend.String("Example Corp."), }, Recipients: []common.Recipient{ { Email: "john@example.com", Name: ahasend.String("John Smith"), }, }, Subject: "Hello", TextContent: ahasend.String("Hello world!"), Sandbox: ahasend.Bool(true), }, api.WithIdempotencyKey("order-"+orderID+"-receipt")) if err != nil { log.Fatalf("Error sending message: %v", err) } // Each recipient gets its own message, or an error saying why it was not sent. for _, message := range response.Data { if message.ID != nil { fmt.Printf("%s: %s\n", message.Recipient.Email, *message.ID) } else if message.Error != nil { fmt.Printf("%s: %s\n", message.Recipient.Email, *message.Error) } }}
import { AhaSendClient } from "@ahasend/sdk";
const client = AhaSendClient.fromEnv();
// The SDK sends a fresh Idempotency-Key automatically and reuses it on its own retries.
const result = await client.messages.send({
from: { email: "sender@example.com", name: "Example" },
recipients: [{ email: "recipient@example.net" }],
subject: "Hello from AhaSend",
html_content: "<p>Hello!</p>",
sandbox: true,
});
console.log("Sandbox message accepted.", { count: result.data.length });
{
"message": "john@example.com: the message could not be rendered: unknown function: nosuch"
}
{
"message": "Error message"
}
{
"message": "Sending from domain 'example.com' is paused. Check your dashboard for the reason."
}
{
"message": "A request with this idempotency key is already in progress"
}
{
"message": "idempotency key was already used with a different request payload"
}
{
"message": "Error message"
}
{
"message": "the message could not be checked right now; try again in a moment"
}
Messages
Send an Email via the API
Send transactional email with the AhaSend API v2: one POST request to up to 100 recipients with templates, attachments, tracking, tags and scheduled sending.
POST
/
v2
/
accounts
/
{account_id}
/
messages
AhaSend Go SDK
package mainimport ( "context" "fmt" "log" "os" "github.com/AhaSend/ahasend-go" "github.com/AhaSend/ahasend-go/api" "github.com/AhaSend/ahasend-go/models/common" "github.com/AhaSend/ahasend-go/models/requests" "github.com/google/uuid")func main() { client := api.NewAPIClient(api.WithAPIKey(os.Getenv("AHASEND_API_KEY"))) accountID := uuid.MustParse(os.Getenv("AHASEND_ACCOUNT_ID")) ctx := context.Background() // The SDK sends a fresh Idempotency-Key with every POST and reuses it on its // own retries. Deriving the key from your own ID instead also makes a rerun // of the same job (after a crash, say) return the first send, not a second. orderID := "1234" response, _, err := client.MessagesAPI.CreateMessage(ctx, accountID, requests.CreateMessageRequest{ From: common.SenderAddress{ Email: "info@example.com", Name: ahasend.String("Example Corp."), }, Recipients: []common.Recipient{ { Email: "john@example.com", Name: ahasend.String("John Smith"), }, }, Subject: "Hello", TextContent: ahasend.String("Hello world!"), Sandbox: ahasend.Bool(true), }, api.WithIdempotencyKey("order-"+orderID+"-receipt")) if err != nil { log.Fatalf("Error sending message: %v", err) } // Each recipient gets its own message, or an error saying why it was not sent. for _, message := range response.Data { if message.ID != nil { fmt.Printf("%s: %s\n", message.Recipient.Email, *message.ID) } else if message.Error != nil { fmt.Printf("%s: %s\n", message.Recipient.Email, *message.Error) } }}
import { AhaSendClient } from "@ahasend/sdk";
const client = AhaSendClient.fromEnv();
// The SDK sends a fresh Idempotency-Key automatically and reuses it on its own retries.
const result = await client.messages.send({
from: { email: "sender@example.com", name: "Example" },
recipients: [{ email: "recipient@example.net" }],
subject: "Hello from AhaSend",
html_content: "<p>Hello!</p>",
sandbox: true,
});
console.log("Sandbox message accepted.", { count: result.data.length });
{
"message": "john@example.com: the message could not be rendered: unknown function: nosuch"
}
{
"message": "Error message"
}
{
"message": "Sending from domain 'example.com' is paused. Check your dashboard for the reason."
}
{
"message": "A request with this idempotency key is already in progress"
}
{
"message": "idempotency key was already used with a different request payload"
}
{
"message": "Error message"
}
{
"message": "the message could not be checked right now; try again in a moment"
}
The AhaSend API creates and sends a message to one or more recipients. This API cannot be used if you want to send a conversational/P2P message and set CC or BCC. Use Create Conversation Message instead. To send a transactional template stored in your account, use Create Template Message.Validation Requirements:
Either text_content or html_content is required
from.email must be from a domain you own with valid DNS records
retention.metadata must be between 1 and 30 days
retention.data must be between 0 and 30 days
If reply_to is provided, do not include reply-to in headers
message-id header will be ignored and automatically generated
Schedule times must be in RFC3339 format
schedule.first_attempt must be in the future and within 7 days of the request
schedule.expires must be in the future and within 8 days of the request
Authorization uses the domain in from.email: either
messages:send:all or the matching domain-specific send role is
sufficient.Template check:
Every message is checked with the template engine before it is sent. Content that the check refuses is answered with 400, and nothing of the request is sent. When the check cannot run right now, the API answers 503 with a Retry-After header: send the same request again after that delay. See API errors.
API key for authentication. Non-empty Security Requirement values are
AhaSend API-key roles. Roles listed within one requirement object are
jointly required; separate requirement objects are alternatives.
Optional idempotency key for safe request retries. Must be a unique string for each logical request.
An identical request with a completed stored outcome returns the original status and body. An in-progress
execution returns 409, a changed method/path/body returns 422, and a released 5xx execution may run again.
Keys for non-secret responses expire after 24 hours. API-key create responses include a one-time secret_key,
so successful encrypted replay responses for those operations expire after 5 minutes.
A {{ variable }} in a subject resolves, whatever else the subject contains -- an emoji or an accented character included -- for every recipient whose message carries substitutions, the request's own substitutions or that recipient's. A recipient with neither is sent nothing to render, so their subject arrives exactly as written, braces and all.
Pad the braces with ordinary spaces: a variable written with non-ASCII whitespace inside them is not reliably recognised.
On a subject that is being resolved and carries an emoji or an accented character, template syntax other than a variable -- {% ... %}, {# ... #} or an unclosed brace -- is rejected. A substitution value is rejected for any of {{, {% or {#, a {{ ... }} included, and so is a subject whose values combine into one of them.
File attachments. For inline images, set the attachment's content_id to a value wrapped in angle brackets (e.g. <image1@example.com>) and reference it from html_content with cid: (e.g. <img src="cid:image1@example.com">).
Custom email headers. Each name must be visible ASCII with no space and no colon. reply-to header cannot be provided if reply_to is provided, message-id will be ignored and automatically generated
Global substitutions, recipient substitutions override global. In the HTML and AMP bodies, values are HTML-escaped; write {{ name|safe }} to insert a value as HTML. The subject, the headers and the text body get values as they are.
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"AhaSend","description":"AhaSend is a European transactional email service for developers: send through a REST API, SMTP relay, CLI or the official Node.js and Go SDKs, with data stored in the EU and 1,000 free emails per month.","colors":{"primary":"#066fd1","light":"#F8FAFC","dark":"#0F172A"},"logo":{"light":"https://mintcdn.com/ahasend/F35Ozd-1GsftDpcH/logo.png?fit=max\u0026auto=format\u0026n=F35Ozd-1GsftDpcH\u0026q=85\u0026s=ca1d4c27f7c2811598e65cb25a21323c","dark":"https://mintcdn.com/ahasend/F35Ozd-1GsftDpcH/logo-dark.png?fit=max\u0026auto=format\u0026n=F35Ozd-1GsftDpcH\u0026q=85\u0026s=bb6b9068b30f93fd1ea216e2a7c1d137","href":"https://ahasend.com/"},"favicon":"https://mintcdn.com/ahasend/F35Ozd-1GsftDpcH/favicon.png?fit=max\u0026auto=format\u0026n=F35Ozd-1GsftDpcH\u0026q=85\u0026s=ac855c16b6cb74b8c5965d2e7ef3e324","appearance":{"strict":false},"navbar":{"links":[{"href":"https://dash.ahasend.com","label":"Login"}],"primary":{"type":"button","label":"Get Started","href":"https://dash.ahasend.com/user/register"}},"footer":{"socials":{"x":"https://x.com/aha_send","linkedin":"https://www.linkedin.com/company/ahasend","github":"https://github.com/ahasend"},"links":[{"header":"Resources","items":[{"label":"Pricing","href":"https://ahasend.com/pricing"},{"label":"Support","href":"mailto:support@ahasend.com"},{"label":"Status","href":"https://status.ahasend.com"},{"label":"Security","href":"https://ahasend.com/security"}]},{"header":"Company","items":[{"label":"Blog","href":"https://ahasend.com/blog"},{"label":"Feedback Board","href":"https://ahasend.sleekplan.app/"}]},{"header":"Legal","items":[{"label":"Imprint","href":"https://ahasend.com/imprint"},{"label":"Terms of Service","href":"https://ahasend.com/terms"},{"label":"Privacy Policy","href":"https://ahasend.com/privacy"},{"label":"Data Processing Agreement","href":"https://ahasend.com/dpa"}]}]},"seo":{"metatags":{"canonical":"https://ahasend.com/docs","twitter:site":"@aha_send"},"organization":{"name":"AhaSend","legalName":"AhaSend B.V.","url":"https://ahasend.com","sameAs":["https://x.com/aha_send","https://www.linkedin.com/company/ahasend","https://github.com/ahasend"]}},"integrations":{"telemetry":{"enabled":true},"cookies":{"key":"cookieConsent","value":"true"}},"errors":{"404":{"redirect":true}},"contextual":{"options":["copy","view","chatgpt","claude"],"display":"header"},"thumbnails":{"appearance":"dark","background":"https://mintcdn.com/ahasend/Gpf8BnLpzpIKQ4dU/images/social-background.svg?fit=max\u0026auto=format\u0026n=Gpf8BnLpzpIKQ4dU\u0026q=85\u0026s=df32e1edef517352b8437c75feecbf6e"},"markdown":{"instructions":["AhaSend stores all message data in the EU. See /facts.","The API base URL is https://api.ahasend.com. Send the API key in the Authorization: Bearer header. See /api-reference/authentication.","Use send.ahasend.com for SMTP. Ports 25, 587 and 2525 use STARTTLS. Port 465 is not supported. See /smtp.","For send-only integrations, create an API Key v2 under Credentials → Add and scope it to messages:send:{your-domain}. See /send-api/credentials and /api-reference/scopes."]},"styling":{"latex":false},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"ahasend","hasAudioNarration":false,"actualSubdomain":"ahasend","customDomains":["ahasend.com"],"gitSource":{"type":"github","owner":"ahasend","repo":"docs","deployBranch":"main","contentDirectory":"","isPrivate":true,"mountPath":"","label":""},"chroma":{"liveDeploymentHistoryId":"6adfc073cd3471cd953b0201","collectionId":"4784fba2-4354-479f-8cd1-66684a92aba7","schemaVersion":"v3","latestBuiltDeploymentHistoryId":"6adfc073cd3471cd953b0201"},"feedback":{"thumbs":true},"entitlements":{},"buildId":"6adfc073cd3471cd953b0201","clientVersion":"0.0.3971","searchFilterCounts":[{"language":"default","tag":"API Reference","count":148},{"language":"default","tag":"API reference","count":114},{"language":"default","tag":"Documentation","count":68},{"language":"default","tag":"Guides","count":52},{"language":"default","tag":"Integrations","count":41},{"language":"default","tag":"Webhooks","count":29},{"language":"default","tag":"CLI","count":25},{"language":"default","tag":"Commands","count":15},{"language":"default","tag":"Domain Authentication","count":13},{"language":"default","tag":"Campaigns","count":12}]},"assistantConfig":{},"basePath":"/docs","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-v7-file-tree","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"pause-universal-search-reconcile","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"per-site-search-delta","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-private-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-nav-generations","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"byok-sep-25","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"vite-origin","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-agent-model-picker","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-updated-9-15","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"privacy":{"consentBanner":{"enabled":false}},"isAtlas":false,"googleFontsInlined":false},"customCss":[{"filePath":"style.css","content":"#content-container table{display:table}#content-container table thead th{text-align:left}"},{"filePath":"roadmap.css","content":".rm{display:flex;flex-direction:column;gap:2.5rem;margin-top:1.5rem}.rm-head{display:flex;align-items:center;gap:.65rem;margin-bottom:1rem}.rm-badge{display:inline-flex;align-items:center;margin:0;border:0;font-size:.78rem;font-weight:600;letter-spacing:.02em;padding:.28rem .75rem;border-radius:999px;line-height:1}.rm-badge.is-active{background:#fdebd0;color:#854f0b}.rm-badge.is-planned{background:#e6f1fb;color:#0c447c}.rm-badge.is-shipped{background:#e1f5ee;color:#0f6e56}.rm-list{display:flex;flex-direction:column;gap:.65rem}.rm-card{display:flex;gap:.9rem;padding:.9rem 1.05rem;background:#fff;border:1px solid #e5e7eb;border-radius:.7rem;transition:transform .15s ease,box-shadow .15s ease}.rm-card:hover{transform:translateY(-1px);box-shadow:0 4px 14px rgba(0,0,0,.06)}.rm-accent{flex:0 0 3px;border-radius:2px}.rm-card.is-active .rm-accent{background:#ba7517}.rm-card.is-planned .rm-accent{background:#378add}.rm-card.is-shipped .rm-accent{background:#1d9e75}.rm-card.is-sub{margin-left:2rem;position:relative}.rm-card p,.rm-card.is-sub .rm-title{font-size:.9rem}.rm-card.is-sub::after,.rm-card.is-sub::before{content:\"\";position:absolute;left:-1.15rem;pointer-events:none}.rm-card.is-sub::before{top:-.65rem;height:calc(100% + .65rem);border-left:1.5px solid #d1d5db}.rm-card.is-sub::after{top:50%;width:.85rem;border-top:1.5px solid #d1d5db}.rm-card .rm-title{margin:0 0 .2rem;font-size:.97rem;font-weight:600;line-height:1.35;color:#111827}.rm-card p{margin:0;line-height:1.55;color:#4b5563}.rm-date,.rm-tag{display:inline-block}.rm-date{margin-top:.5rem;font-size:.78rem;font-weight:600;color:#0f6e56}.rm-tag{margin-left:.5rem;font-size:.66rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;padding:.16rem .5rem;border-radius:999px;vertical-align:middle;line-height:1.4;color:#fff;box-shadow:0 1px 2px rgba(0,0,0,.15)}.rm-tag.is-new{background:#6d28d9}.rm-tag.is-product{background:#be123c}.rm-tag.is-improvement{background:#0e7490}.rm-tag.is-early{background:#1d4ed8}.rm-tag.is-bugfix{background:#c2410c}.dark .rm-card{background:rgba(255,255,255,.025);border-color:rgba(255,255,255,.09)}.dark .rm-card p{color:#9ca3af}.dark .rm-badge.is-active{background:rgba(186,117,23,.18);color:#fac074}.dark .rm-badge.is-planned{background:rgba(55,138,221,.18);color:#85b7eb}.dark .rm-badge.is-shipped{background:rgba(29,158,117,.18);color:#5dcaa5}.dark .rm-date{color:#5dcaa5}.dark .rm-card.is-sub::after,.dark .rm-card.is-sub::before{border-color:rgba(255,255,255,.18)}.rm-note{margin-top:2.5rem;font-size:.85rem;color:#6b7280}.dark .rm-note{color:#9ca3af}.dark .rm-card .rm-title{color:#e7e9ee}.rm-jump{margin:-.5rem 0 0;font-size:.88rem}.rm-jump a{color:#2296ff;text-decoration:none;font-weight:500}.rm-jump a:hover{text-decoration:underline}.rm-badge[id]{scroll-margin-top:6rem}"}],"page":{"pagePath":"api-reference/messages/create-message","slug":"/api-reference/messages/create-message","pageMetadata":{"title":"Send an Email via the API","sidebarTitle":"Create Message","openapi":"openapi.yaml POST /v2/accounts/{account_id}/messages","description":"Send transactional email with the AhaSend API v2: one POST request to up to 100 recipients with templates, attachments, tracking, tags and scheduled sending.","href":"/api-reference/messages/create-message"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Send transactional email with the AhaSend API v2: one POST request to up to 100 recipients with templates, attachments, tracking, tags and scheduled sending.\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,code:`code`,li:`li`,p:`p`,strong:`strong`,ul:`ul`,..._provideComponents(),...props.components},{Heading}=_components;if(!Heading)_missingMdxReference(`Heading`,true);return _jsxs(_Fragment,{children:[_jsxs(_components.p,{children:[`The AhaSend API creates and sends a message to one or more recipients. This API cannot be used if you want to send a conversational/P2P message and set CC or BCC. Use `,_jsx(_components.a,{href:`/api-reference/messages/create-conversation`,children:`Create Conversation Message`}),` instead. To send a transactional template stored in your account, use `,_jsx(_components.a,{href:`/api-reference/messages/create-template-message`,children:`Create Template Message`}),`.`]}),`\n`,_jsx(_components.p,{children:_jsx(_components.strong,{children:`Validation Requirements:`})}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`Either `,_jsx(_components.code,{children:`text_content`}),` or `,_jsx(_components.code,{children:`html_content`}),` is required`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`from.email`}),` must be from a domain you own with valid DNS records`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`retention.metadata`}),` must be between 1 and 30 days`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`retention.data`}),` must be between 0 and 30 days`]}),`\n`,_jsxs(_components.li,{children:[`If `,_jsx(_components.code,{children:`reply_to`}),` is provided, do not include `,_jsx(_components.code,{children:`reply-to`}),` in headers`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`message-id`}),` header will be ignored and automatically generated`]}),`\n`,_jsx(_components.li,{children:`Schedule times must be in RFC3339 format`}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`schedule.first_attempt`}),` must be in the future and within 7 days of the request`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`schedule.expires`}),` must be in the future and within 8 days of the request`]}),`\n`]}),`\n`,_jsxs(_components.p,{children:[`Authorization uses the domain in `,_jsx(_components.code,{children:`from.email`}),`: either\n`,_jsx(_components.code,{children:`messages:send:all`}),` or the matching domain-specific send role is\nsufficient.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Template check:`}),`\nEvery message is checked with the template engine before it is sent. Content that the check refuses is answered with `,_jsx(_components.code,{children:`400`}),`, and nothing of the request is sent. When the check cannot run right now, the API answers `,_jsx(_components.code,{children:`503`}),` with a `,_jsx(_components.code,{children:`Retry-After`}),` header: send the same request again after that delay. See `,_jsx(_components.a,{href:`/api-reference/errors#400-bad-request`,children:`API errors`}),`.`]}),`\n`,_jsx(Heading,{level:`2`,id:`related-guides`,children:`Related Guides`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`Before sending: `,_jsx(_components.a,{href:`/domains`,children:`verify your sender domain`}),`.`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[_jsx(_components.a,{href:`/api-reference/authentication`,children:`API authentication`}),`, `,_jsx(_components.a,{href:`/api-reference/scopes`,children:`Permission scopes`}),`, `,_jsx(_components.a,{href:`/send-api/send-email`,children:`Sending guide`}),`.`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[_jsx(_components.a,{href:`/cli/commands/messages`,children:`Message CLI`}),`, `,_jsx(_components.a,{href:`/smtp`,children:`SMTP settings`}),`, `,_jsx(_components.a,{href:`/guides/nodejs-sdk`,children:`Node.js SDK`}),`.`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[_jsx(_components.a,{href:`/guides/go-sdk`,children:`Go SDK`}),`, `,_jsx(_components.a,{href:`/api-reference/errors`,children:`API errors`}),`, `,_jsx(_components.a,{href:`/api-reference/rate-limits`,children:`API rate limits`}),`.`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[_jsx(_components.a,{href:`/retention`,children:`Retention rules`}),`.`]}),`\n`]}),`\n`]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Send an Email via the API","sidebarTitle":"Create Message","openapi":"openapi.yaml POST /v2/accounts/{account_id}/messages","description":"Send transactional email with the AhaSend API v2: one POST request to up to 100 recipients with templates, attachments, tracking, tags and scheduled sending.","href":"/api-reference/messages/create-message"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"Related Guides","slug":"related-guides","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":["/docs/_mintlify/custom/ahasend/1d760da0535d9f7c/ahasend-gtm.js"],"openApiReferenceData":{"operation":{"summary":"Create Message","description":"Send transactional email with the AhaSend API v2: one POST request to up to 100 recipients with templates, attachments, tracking, tags and scheduled sending.","operationId":"createMessage","tags":["Messages"],"parameters":["aea5a7cd-b709-4c0e-ac1e-4e3b2c38c60f","2ce70ee3-a3d8-48de-b01c-01660d6311fb"],"security":["8977136d-3724-4f28-a22c-fe08a987ae9a","e0498769-971e-49e2-8041-a720250a54b9"],"x-code-samples":[{"lang":"go","label":"AhaSend Go SDK","source":"package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n \"os\"\n\n \"github.com/AhaSend/ahasend-go\"\n \"github.com/AhaSend/ahasend-go/api\"\n \"github.com/AhaSend/ahasend-go/models/common\"\n \"github.com/AhaSend/ahasend-go/models/requests\"\n \"github.com/google/uuid\"\n)\n\nfunc main() {\n client := api.NewAPIClient(api.WithAPIKey(os.Getenv(\"AHASEND_API_KEY\")))\n accountID := uuid.MustParse(os.Getenv(\"AHASEND_ACCOUNT_ID\"))\n ctx := context.Background()\n\n // The SDK sends a fresh Idempotency-Key with every POST and reuses it on its\n // own retries. Deriving the key from your own ID instead also makes a rerun\n // of the same job (after a crash, say) return the first send, not a second.\n orderID := \"1234\"\n\n response, _, err := client.MessagesAPI.CreateMessage(ctx, accountID, requests.CreateMessageRequest{\n From: common.SenderAddress{\n Email: \"info@example.com\",\n Name: ahasend.String(\"Example Corp.\"),\n },\n Recipients: []common.Recipient{\n {\n Email: \"john@example.com\",\n Name: ahasend.String(\"John Smith\"),\n },\n },\n Subject: \"Hello\",\n TextContent: ahasend.String(\"Hello world!\"),\n Sandbox: ahasend.Bool(true),\n }, api.WithIdempotencyKey(\"order-\"+orderID+\"-receipt\"))\n if err != nil {\n log.Fatalf(\"Error sending message: %v\", err)\n }\n // Each recipient gets its own message, or an error saying why it was not sent.\n for _, message := range response.Data {\n if message.ID != nil {\n fmt.Printf(\"%s: %s\\n\", message.Recipient.Email, *message.ID)\n } else if message.Error != nil {\n fmt.Printf(\"%s: %s\\n\", message.Recipient.Email, *message.Error)\n }\n }\n}\n"},{"lang":"javascript","label":"Node.js 22+ (AhaSend SDK)","source":"import { AhaSendClient } from \"@ahasend/sdk\";\n\nconst client = AhaSendClient.fromEnv();\n// The SDK sends a fresh Idempotency-Key automatically and reuses it on its own retries.\nconst result = await client.messages.send({\n from: { email: \"sender@example.com\", name: \"Example\" },\n recipients: [{ email: \"recipient@example.net\" }],\n subject: \"Hello from AhaSend\",\n html_content: \"\u003cp>Hello!\u003c/p>\",\n sandbox: true,\n});\nconsole.log(\"Sandbox message accepted.\", { count: result.data.length });\n"}],"requestBody":"118c4cd7-4bcc-45c4-831a-7557141b97db","responses":{"202":"5c7dd9c3-a052-4f15-b48a-52e7a1d7d936","400":"a6353bb6-f96e-4ee0-a6fe-765596e153a8","401":"d7c2f171-f942-4183-add5-78e9a8dd34f3","403":"52932e73-8a4d-4f14-9b15-b71b9f6af6f9","409":"23582bee-2642-4210-8870-3e901dd89646","422":"dd8d9d5c-3990-4a47-a022-5d4a63c7d31d","500":"2f44c4fc-7c49-452c-b0a9-d0c2261c6ec4","503":"96ac32d4-9a8f-4e9d-a575-97465960ef92"},"method":"post","type":"path","servers":["86d7498e-4af6-401e-8ea8-8da69eeecaa7"],"path":"/v2/accounts/{account_id}/messages","baseUrlOptions":["https://api.ahasend.com"],"title":"Create Message","codeSamples":[{"label":"AhaSend Go SDK","lang":"go","source":"package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n \"os\"\n\n \"github.com/AhaSend/ahasend-go\"\n \"github.com/AhaSend/ahasend-go/api\"\n \"github.com/AhaSend/ahasend-go/models/common\"\n \"github.com/AhaSend/ahasend-go/models/requests\"\n \"github.com/google/uuid\"\n)\n\nfunc main() {\n client := api.NewAPIClient(api.WithAPIKey(os.Getenv(\"AHASEND_API_KEY\")))\n accountID := uuid.MustParse(os.Getenv(\"AHASEND_ACCOUNT_ID\"))\n ctx := context.Background()\n\n // The SDK sends a fresh Idempotency-Key with every POST and reuses it on its\n // own retries. Deriving the key from your own ID instead also makes a rerun\n // of the same job (after a crash, say) return the first send, not a second.\n orderID := \"1234\"\n\n response, _, err := client.MessagesAPI.CreateMessage(ctx, accountID, requests.CreateMessageRequest{\n From: common.SenderAddress{\n Email: \"info@example.com\",\n Name: ahasend.String(\"Example Corp.\"),\n },\n Recipients: []common.Recipient{\n {\n Email: \"john@example.com\",\n Name: ahasend.String(\"John Smith\"),\n },\n },\n Subject: \"Hello\",\n TextContent: ahasend.String(\"Hello world!\"),\n Sandbox: ahasend.Bool(true),\n }, api.WithIdempotencyKey(\"order-\"+orderID+\"-receipt\"))\n if err != nil {\n log.Fatalf(\"Error sending message: %v\", err)\n }\n // Each recipient gets its own message, or an error saying why it was not sent.\n for _, message := range response.Data {\n if message.ID != nil {\n fmt.Printf(\"%s: %s\\n\", message.Recipient.Email, *message.ID)\n } else if message.Error != nil {\n fmt.Printf(\"%s: %s\\n\", message.Recipient.Email, *message.Error)\n }\n }\n}\n"},{"label":"Node.js 22+ (AhaSend SDK)","lang":"javascript","source":"import { AhaSendClient } from \"@ahasend/sdk\";\n\nconst client = AhaSendClient.fromEnv();\n// The SDK sends a fresh Idempotency-Key automatically and reuses it on its own retries.\nconst result = await client.messages.send({\n from: { email: \"sender@example.com\", name: \"Example\" },\n recipients: [{ email: \"recipient@example.net\" }],\n subject: \"Hello from AhaSend\",\n html_content: \"\u003cp>Hello!\u003c/p>\",\n sandbox: true,\n});\nconsole.log(\"Sandbox message accepted.\", { count: result.data.length });\n"}],"requiredOnlyExamples":false,"requestExampleType":"codeSamples","responseExampleType":"generated"},"dependencies":{"parameters":{"aea5a7cd-b709-4c0e-ac1e-4e3b2c38c60f":{"name":"account_id","in":"path","required":true,"description":"Account ID","schema":{"type":"string","format":"uuid","isRequired":true,"description":"Account ID","uniqueKey":"","typeLabel":"string\u003cuuid>"}},"2ce70ee3-a3d8-48de-b01c-01660d6311fb":{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional idempotency key for safe request retries. Must be a unique string for each logical request.\nAn identical request with a completed stored outcome returns the original status and body. An in-progress\nexecution returns 409, a changed method/path/body returns 422, and a released 5xx execution may run again.\nKeys for non-secret responses expire after 24 hours. API-key create responses include a one-time `secret_key`,\nso successful encrypted replay responses for those operations expire after 5 minutes.\n","schema":{"type":"string","maxLength":255,"isRequired":false,"description":"Optional idempotency key for safe request retries. Must be a unique string for each logical request.\nAn identical request with a completed stored outcome returns the original status and body. An in-progress\nexecution returns 409, a changed method/path/body returns 422, and a released 5xx execution may run again.\nKeys for non-secret responses expire after 24 hours. API-key create responses include a one-time `secret_key`,\nso successful encrypted replay responses for those operations expire after 5 minutes.\n","uniqueKey":"","typeLabel":"string"},"example":"user-12345-create-domain-20240101"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["from","recipients","subject"],"properties":{"from":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email","description":"The email address. A `from` address must be on a domain defined in your account with valid DNS records.","isRequired":true,"uniqueKey":"from.email","typeLabel":"string\u003cemail>"},"name":{"type":"string","description":"The display name shown with the address. It can hold any Unicode text; the API encodes it for the header. On a send with substitutions or a template, a name with non-ASCII text can use `{{ name }}` references only; other template syntax in it is refused.","uniqueKey":"from.name","typeLabel":"string"}},"example":{"email":"noreply@example.com","name":"Example Corp"},"isRequired":true,"uniqueKey":"from","typeLabel":"object"},"recipients":{"type":"array","items":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email","description":"Recipient email address","isRequired":true,"uniqueKey":"recipients.items.[INDEX].email","typeLabel":"string\u003cemail>"},"name":{"type":"string","description":"Display name for the recipient. It can hold any Unicode text; the API encodes it for the header. On a send with substitutions or a template, a name with non-ASCII text can use `{{ name }}` references only; other template syntax in it is refused.","uniqueKey":"recipients.items.[INDEX].name","typeLabel":"string"},"substitutions":{"type":"object","additionalProperties":true,"description":"Substitution data for the recipient. Used with jinja2 templating language for dynamic content. In the HTML and AMP bodies, values are HTML-escaped; write `{{ name|safe }}` to insert a value as HTML. The subject, the headers and the text body get values as they are. On a template send, to fill a `list` variable, send an array; the template's `variables` show the fields each element needs.","uniqueKey":"recipients.items.[INDEX].substitutions","typeLabel":"object"}},"example":{"email":"user@example.com","name":"John Doe","substitutions":{"first_name":"John","order_id":"12345"}},"uniqueKey":"recipients.items.[INDEX]","typeLabel":"object"},"minItems":1,"maxItems":100,"description":"This does not set the To header to multiple addresses, it sends a separate message for each recipient","isRequired":true,"uniqueKey":"recipients","typeLabel":"object[]"},"subject":{"type":"string","description":"Email subject line.\n\nA `{{ variable }}` in a subject resolves, whatever else the subject contains -- an emoji or an accented character included -- for every recipient whose message carries substitutions, the request's own `substitutions` or that recipient's. A recipient with neither is sent nothing to render, so their subject arrives exactly as written, braces and all.\n\nPad the braces with ordinary spaces: a variable written with non-ASCII whitespace inside them is not reliably recognised.\n\nOn a subject that is being resolved and carries an emoji or an accented character, template syntax other than a variable -- `{% ... %}`, `{# ... #}` or an unclosed brace -- is rejected. A substitution value is rejected for any of `{{`, `{%` or `{#`, a `{{ ... }}` included, and so is a subject whose values combine into one of them.\n","isRequired":true,"uniqueKey":"subject","typeLabel":"string"},"reply_to":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email","description":"The email address. A `from` address must be on a domain defined in your account with valid DNS records.","isRequired":true,"uniqueKey":"reply_to.email","typeLabel":"string\u003cemail>"},"name":{"type":"string","description":"The display name shown with the address. It can hold any Unicode text; the API encodes it for the header. On a send with substitutions or a template, a name with non-ASCII text can use `{{ name }}` references only; other template syntax in it is refused.","uniqueKey":"reply_to.name","typeLabel":"string"}},"example":{"email":"noreply@example.com","name":"Example Corp"},"description":"If provided, the reply-to header in headers array must not be provided","uniqueKey":"reply_to","typeLabel":"object"},"text_content":{"type":"string","description":"Plain text content. Required if html_content is empty","uniqueKey":"text_content","typeLabel":"string"},"html_content":{"type":"string","description":"HTML content. Required if text_content is empty","uniqueKey":"html_content","typeLabel":"string"},"amp_content":{"type":"string","description":"AMP HTML content","uniqueKey":"amp_content","typeLabel":"string"},"attachments":{"type":"array","items":{"type":"object","required":["data","content_type","file_name"],"properties":{"data":{"type":"string","description":"Either plaintext or base64 encoded attachment data (depending on base64 field)","isRequired":true,"uniqueKey":"attachments.items.[INDEX].data","typeLabel":"string"},"content_type":{"type":"string","description":"The MIME type of the attachment","isRequired":true,"uniqueKey":"attachments.items.[INDEX].content_type","typeLabel":"string"},"file_name":{"type":"string","description":"The filename of the attachment","isRequired":true,"uniqueKey":"attachments.items.[INDEX].file_name","typeLabel":"string"},"base64":{"type":"boolean","description":"If true, data must be encoded using base64. Otherwise, data will be interpreted as UTF-8","default":false,"uniqueKey":"attachments.items.[INDEX].base64","typeLabel":"boolean"},"content_disposition":{"type":"string","description":"The disposition of the attachment","uniqueKey":"attachments.items.[INDEX].content_disposition","typeLabel":"string"},"content_id":{"type":"string","description":"Content-ID that lets you reference this attachment as an inline image from your HTML.\n\nThe value **must be wrapped in angle brackets**, matching the MIME `Content-ID` header format — for example `\"\u003cimage1@example.com>\"`. Reference it from `html_content` **without** the brackets, e.g. `\u003cimg src=\"cid:image1@example.com\">`.\n\nIf the angle brackets are omitted, the file is delivered as a regular (downloadable) attachment instead of rendering inline.\n","uniqueKey":"attachments.items.[INDEX].content_id","typeLabel":"string"}},"example":{"base64":true,"data":"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==","content_type":"image/png","file_name":"pixel.png"},"uniqueKey":"attachments.items.[INDEX]","typeLabel":"object"},"description":"File attachments. For inline images, set the attachment's `content_id` to a value wrapped in angle brackets (e.g. `\u003cimage1@example.com>`) and reference it from `html_content` with `cid:` (e.g. `\u003cimg src=\"cid:image1@example.com\">`).","uniqueKey":"attachments","typeLabel":"object[]"},"headers":{"type":"object","additionalProperties":{"type":"string","uniqueKey":"headers.additionalProperties","typeLabel":"string"},"description":"Custom email headers. Each name must be visible ASCII with no space and no colon. reply-to header cannot be provided if reply_to is provided, message-id will be ignored and automatically generated","uniqueKey":"headers","typeLabel":"object"},"substitutions":{"type":"object","additionalProperties":true,"description":"Global substitutions, recipient substitutions override global. In the HTML and AMP bodies, values are HTML-escaped; write `{{ name|safe }}` to insert a value as HTML. The subject, the headers and the text body get values as they are.","uniqueKey":"substitutions","typeLabel":"object"},"tags":{"type":"array","items":{"type":"string","uniqueKey":"tags.items.[INDEX]","typeLabel":"string"},"description":"Tags for categorizing messages","uniqueKey":"tags","typeLabel":"string[]"},"sandbox":{"type":"boolean","description":"If true, the message will be sent to the sandbox environment","default":false,"uniqueKey":"sandbox","typeLabel":"boolean"},"sandbox_result":{"type":"string","enum":["deliver","bounce","defer","fail","suppress"],"description":"The result of the sandbox send","uniqueKey":"sandbox_result","typeLabel":"enum\u003cstring>"},"tracking":{"oneOf":[{"type":"object","properties":{"open":{"oneOf":[{"type":"boolean","description":"Whether to track opens","uniqueKey":"tracking.oneOf.0.open.oneOf.0","typeLabel":"boolean"},{"type":"null","description":"Whether to track opens","uniqueKey":"tracking.oneOf.0.open.oneOf.1","typeLabel":"null"}],"uniqueKey":"tracking.oneOf.0.open","typeLabel":"boolean | null"},"click":{"oneOf":[{"type":"boolean","description":"Whether to track clicks","uniqueKey":"tracking.oneOf.0.click.oneOf.0","typeLabel":"boolean"},{"type":"null","description":"Whether to track clicks","uniqueKey":"tracking.oneOf.0.click.oneOf.1","typeLabel":"null"}],"uniqueKey":"tracking.oneOf.0.click","typeLabel":"boolean | null"}},"example":{"open":true,"click":true},"description":"Tracking settings for the message, overrides default account settings","uniqueKey":"tracking.oneOf.0","typeLabel":"object"},{"type":"null","properties":{"open":{"oneOf":[{"type":"boolean","description":"Whether to track opens"},{"type":"null","description":"Whether to track opens"}]},"click":{"oneOf":[{"type":"boolean","description":"Whether to track clicks"},{"type":"null","description":"Whether to track clicks"}]}},"example":{"open":true,"click":true},"description":"Tracking settings for the message, overrides default account settings","uniqueKey":"tracking.oneOf.1","typeLabel":"null"}],"uniqueKey":"tracking","typeLabel":"object | null"},"retention":{"oneOf":[{"type":"object","properties":{"metadata":{"oneOf":[{"type":"integer","description":"Number of days to retain metadata","minimum":1,"maximum":30,"uniqueKey":"retention.oneOf.0.metadata.oneOf.0","typeLabel":"integer"},{"type":"null","description":"Number of days to retain metadata","minimum":1,"maximum":30,"uniqueKey":"retention.oneOf.0.metadata.oneOf.1","typeLabel":"null"}],"uniqueKey":"retention.oneOf.0.metadata","typeLabel":"integer | null"},"data":{"oneOf":[{"type":"integer","description":"Number of days to retain data","minimum":0,"maximum":30,"uniqueKey":"retention.oneOf.0.data.oneOf.0","typeLabel":"integer"},{"type":"null","description":"Number of days to retain data","minimum":0,"maximum":30,"uniqueKey":"retention.oneOf.0.data.oneOf.1","typeLabel":"null"}],"uniqueKey":"retention.oneOf.0.data","typeLabel":"integer | null"}},"example":{"metadata":1,"data":0},"description":"Retention settings for the message, overrides default account settings","uniqueKey":"retention.oneOf.0","typeLabel":"object"},{"type":"null","properties":{"metadata":{"oneOf":[{"type":"integer","description":"Number of days to retain metadata","minimum":1,"maximum":30},{"type":"null","description":"Number of days to retain metadata","minimum":1,"maximum":30}]},"data":{"oneOf":[{"type":"integer","description":"Number of days to retain data","minimum":0,"maximum":30},{"type":"null","description":"Number of days to retain data","minimum":0,"maximum":30}]}},"example":{"metadata":1,"data":0},"description":"Retention settings for the message, overrides default account settings","uniqueKey":"retention.oneOf.1","typeLabel":"null"}],"uniqueKey":"retention","typeLabel":"object | null"},"schedule":{"type":"object","properties":{"first_attempt":{"type":"string","format":"date-time","description":"The time to make the first attempt for delivering the message. Must be RFC3339 format, in the future, and within 7 days of the request.","uniqueKey":"schedule.first_attempt","typeLabel":"string\u003cdate-time>"},"expires":{"type":"string","format":"date-time","description":"Expire and drop the message if not delivered by this time. Must be RFC3339 format, in the future, and within 8 days of the request.","uniqueKey":"schedule.expires","typeLabel":"string\u003cdate-time>"}},"description":"Schedule for message delivery","uniqueKey":"schedule","typeLabel":"object"}},"example":{"from":{"email":"noreply@example.com","name":"Example Corp"},"recipients":[{"email":"user@example.com","name":"John Doe"}],"subject":"Welcome to Example Corp","html_content":"\u003ch1>Welcome {{first_name}}!\u003c/h1>","text_content":"Welcome {{first_name}}!","substitutions":{"first_name":"John"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"from":{"email":"noreply@example.com","name":"Example Corp"},"recipients":[{"email":"user@example.com","name":"John Doe"}],"subject":"Welcome to Example Corp","html_content":"\u003ch1>Welcome {{first_name}}!\u003c/h1>","text_content":"Welcome {{first_name}}!","substitutions":{"first_name":"John"}}}},"exampleType":"generated"}},"exampleType":"generated"},"responses":{"5c7dd9c3-a052-4f15-b48a-52e7a1d7d936":{"description":"Message created successfully","headers":{"Idempotent-Replayed":{"description":"Indicates that this response is a stored replay of a previous identical request.\nWhen this header is absent, the response is not a stored replay. Ordinary fresh\nresponses do not send `false`; that value is reserved for an in-progress 409.\n","schema":{"type":"string","enum":["true"]}}},"content":{"application/json":{"schema":{"type":"object","required":["object","data"],"properties":{"object":{"type":"string","enum":["list"],"description":"Object type identifier","isRequired":true,"uniqueKey":"object","typeLabel":"enum\u003cstring>"},"data":{"type":"array","items":{"type":"object","required":["object","id","recipient","status","error"],"properties":{"object":{"type":"string","enum":["message"],"description":"Object type identifier","isRequired":true,"uniqueKey":"data.items.[INDEX].object","typeLabel":"enum\u003cstring>"},"id":{"oneOf":[{"type":"string","description":"Message ID (null if the message was not sent)","example":"\u003cuuid@example.com>","isRequired":true,"uniqueKey":"data.items.[INDEX].id.oneOf.0","typeLabel":"string"},{"type":"null","description":"Message ID (null if the message was not sent)","example":"\u003cuuid@example.com>","isRequired":true,"uniqueKey":"data.items.[INDEX].id.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"data.items.[INDEX].id","typeLabel":"string | null"},"recipient":{"type":"object","required":["name","email"],"example":{"email":"user@example.com","name":"John Doe","substitutions":{"first_name":"John","order_id":"12345"}},"properties":{"email":{"type":"string","format":"email","description":"Recipient email address","isRequired":true,"uniqueKey":"data.items.[INDEX].recipient.email","typeLabel":"string\u003cemail>"},"name":{"type":"string","description":"Display name for the recipient. It can hold any Unicode text; the API encodes it for the header. On a send with substitutions or a template, a name with non-ASCII text can use `{{ name }}` references only; other template syntax in it is refused.","isRequired":true,"uniqueKey":"data.items.[INDEX].recipient.name","typeLabel":"string"},"substitutions":{"type":"object","additionalProperties":true,"description":"Substitution data for the recipient. Used with jinja2 templating language for dynamic content. In the HTML and AMP bodies, values are HTML-escaped; write `{{ name|safe }}` to insert a value as HTML. The subject, the headers and the text body get values as they are. On a template send, to fill a `list` variable, send an array; the template's `variables` show the fields each element needs.","uniqueKey":"data.items.[INDEX].recipient.substitutions","typeLabel":"object"}},"isRequired":true,"uniqueKey":"data.items.[INDEX].recipient","typeLabel":"object"},"status":{"type":"string","enum":["queued","scheduled","error"],"description":"Status of the message","isRequired":true,"uniqueKey":"data.items.[INDEX].status","typeLabel":"enum\u003cstring>"},"error":{"oneOf":[{"type":"string","description":"Error message if the message was not sent","isRequired":true,"uniqueKey":"data.items.[INDEX].error.oneOf.0","typeLabel":"string"},{"type":"null","description":"Error message if the message was not sent","isRequired":true,"uniqueKey":"data.items.[INDEX].error.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"data.items.[INDEX].error","typeLabel":"string | null"},"schedule":{"type":"object","properties":{"first_attempt":{"type":"string","format":"date-time","description":"The time to make the first attempt for delivering the message. Must be RFC3339 format, in the future, and within 7 days of the request.","uniqueKey":"data.items.[INDEX].schedule.first_attempt","typeLabel":"string\u003cdate-time>"},"expires":{"type":"string","format":"date-time","description":"Expire and drop the message if not delivered by this time. Must be RFC3339 format, in the future, and within 8 days of the request.","uniqueKey":"data.items.[INDEX].schedule.expires","typeLabel":"string\u003cdate-time>"}},"description":"Provided if the request contained a schedule","uniqueKey":"data.items.[INDEX].schedule","typeLabel":"object"}},"uniqueKey":"data.items.[INDEX]","typeLabel":"object"},"description":"List of messages and their statuses","isRequired":true,"uniqueKey":"data","typeLabel":"object[]"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"object":"list","data":[{"object":"message","id":"\u003cuuid@example.com>","recipient":{"email":"user@example.com","name":"John Doe","substitutions":{"first_name":"John","order_id":"12345"}},"status":"queued","error":"\u003cstring>","schedule":{"first_attempt":"2023-11-07T05:31:56Z","expires":"2023-11-07T05:31:56Z"}}]}}},"exampleType":"generated"}},"exampleType":"generated"},"a6353bb6-f96e-4ee0-a6fe-765596e153a8":{"description":"Bad request. Every message is checked before it is sent. A message is refused, and nothing of the request is sent, when its content cannot be rendered with a recipient's values, calls `random`, `randrange`, `lipsum` or `now`, uses `namespace`, passes a work, output, memory or time limit, or has a recipient address the check cannot read. The message is `\u003cemail>: the message could not be rendered: \u003creason>`, or without `\u003cemail>: ` when no recipient had started rendering. A refused request with an `Idempotency-Key` gets the same answer again for that key.\n","content":{"application/json":{"schema":{"type":"object","description":"Human-readable API error. The server currently sends no stable machine\nerror code. In particular, clients must not parse `message` to\ndistinguish IP-allow-list, scope, ownership, plan, self-lockout,\nsuppression-duplicate, or other errors that share an HTTP status.\n","additionalProperties":false,"required":["message"],"properties":{"message":{"type":"string","description":"Error description","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"example":{"message":"Error message"},"uniqueKey":"","typeLabel":"object"},"examples":{"render_refused":{"title":"render_refused","value":{"message":"john@example.com: the message could not be rendered: unknown function: nosuch"}}},"exampleType":"examples"}},"exampleType":"examples"},"d7c2f171-f942-4183-add5-78e9a8dd34f3":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","description":"Human-readable API error. The server currently sends no stable machine\nerror code. In particular, clients must not parse `message` to\ndistinguish IP-allow-list, scope, ownership, plan, self-lockout,\nsuppression-duplicate, or other errors that share an HTTP status.\n","additionalProperties":false,"required":["message"],"properties":{"message":{"type":"string","description":"Error description","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"example":{"message":"Error message"},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"message":"Error message"}}},"exampleType":"generated"}},"exampleType":"generated"},"52932e73-8a4d-4f14-9b15-b71b9f6af6f9":{"description":"Forbidden. For example, the API key cannot send from the domain, the account cannot send, or sending from the domain is paused. A sandbox message is accepted from a paused domain.\n","content":{"application/json":{"schema":{"type":"object","description":"Human-readable API error. The server currently sends no stable machine\nerror code. In particular, clients must not parse `message` to\ndistinguish IP-allow-list, scope, ownership, plan, self-lockout,\nsuppression-duplicate, or other errors that share an HTTP status.\n","additionalProperties":false,"required":["message"],"properties":{"message":{"type":"string","description":"Error description","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"example":{"message":"Error message"},"uniqueKey":"","typeLabel":"object"},"examples":{"domain_paused":{"title":"domain_paused","value":{"message":"Sending from domain 'example.com' is paused. Check your dashboard for the reason."}}},"exampleType":"examples"}},"exampleType":"examples"},"23582bee-2642-4210-8870-3e901dd89646":{"description":"Request in progress. This response always includes\n`Idempotent-Replayed: false` and a positive integer `Retry-After`.\nClients must use that header tuple, not the human-readable message, to\ndistinguish this retryable idempotency state from other HTTP 409s.\n","headers":{"Idempotent-Replayed":{"description":"Identifies an idempotency-key execution that is still in progress. This\nheader is emitted only on the specialized HTTP 409 response.\n","schema":{"type":"string","enum":["false"]}},"Retry-After":{"description":"Positive whole number of seconds after which the in-progress execution\nlease may be retried with the same key and unchanged request.\n","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"type":"object","description":"Human-readable API error. The server currently sends no stable machine\nerror code. In particular, clients must not parse `message` to\ndistinguish IP-allow-list, scope, ownership, plan, self-lockout,\nsuppression-duplicate, or other errors that share an HTTP status.\n","additionalProperties":false,"required":["message"],"properties":{"message":{"type":"string","description":"Error description","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"example":{"message":"Error message"},"uniqueKey":"","typeLabel":"object"},"example":{"message":"A request with this idempotency key is already in progress"},"examples":{"Example":{"title":"Example","value":{"message":"A request with this idempotency key is already in progress"}}},"exampleType":"examples"}},"exampleType":"examples"},"dd8d9d5c-3990-4a47-a022-5d4a63c7d31d":{"description":"Idempotency key was already used with a different HTTP method, resolved\nrequest path, or request body. This response includes neither\n`Idempotent-Replayed` nor `Retry-After`.\n","content":{"application/json":{"schema":{"type":"object","description":"Human-readable API error. The server currently sends no stable machine\nerror code. In particular, clients must not parse `message` to\ndistinguish IP-allow-list, scope, ownership, plan, self-lockout,\nsuppression-duplicate, or other errors that share an HTTP status.\n","additionalProperties":false,"required":["message"],"properties":{"message":{"type":"string","description":"Error description","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"example":{"message":"Error message"},"uniqueKey":"","typeLabel":"object"},"example":{"message":"idempotency key was already used with a different request payload"},"examples":{"Example":{"title":"Example","value":{"message":"idempotency key was already used with a different request payload"}}},"exampleType":"examples"}},"exampleType":"examples"},"2f44c4fc-7c49-452c-b0a9-d0c2261c6ec4":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","description":"Human-readable API error. The server currently sends no stable machine\nerror code. In particular, clients must not parse `message` to\ndistinguish IP-allow-list, scope, ownership, plan, self-lockout,\nsuppression-duplicate, or other errors that share an HTTP status.\n","additionalProperties":false,"required":["message"],"properties":{"message":{"type":"string","description":"Error description","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"example":{"message":"Error message"},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"message":"Error message"}}},"exampleType":"generated"}},"exampleType":"generated"},"96ac32d4-9a8f-4e9d-a575-97465960ef92":{"description":"Every message is checked with the template engine before it is sent,\nand the check could not run right now: the service was busy, or the\nengine failed. Nothing was sent and nothing is known to be wrong with\nthe message.\nSend it again after `Retry-After` seconds; on an operation that takes\nan `Idempotency-Key`, send it with the same key.\n","headers":{"Retry-After":{"description":"Seconds to wait before retrying","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"type":"object","description":"Human-readable API error. The server currently sends no stable machine\nerror code. In particular, clients must not parse `message` to\ndistinguish IP-allow-list, scope, ownership, plan, self-lockout,\nsuppression-duplicate, or other errors that share an HTTP status.\n","additionalProperties":false,"required":["message"],"properties":{"message":{"type":"string","description":"Error description","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"example":{"message":"Error message"},"uniqueKey":"","typeLabel":"object"},"example":{"message":"the message could not be checked right now; try again in a moment"},"examples":{"Example":{"title":"Example","value":{"message":"the message could not be checked right now; try again in a moment"}}},"exampleType":"examples"}},"exampleType":"examples"}},"security":{"8977136d-3724-4f28-a22c-fe08a987ae9a":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"aha-sk-64-CHARACTER-RANDOM-STRING","description":"API key for authentication. Non-empty Security Requirement values are\nAhaSend API-key roles. Roles listed within one requirement object are\njointly required; separate requirement objects are alternatives.\n","scopes":["messages:send:all"],"schemeName":"BearerAuth"}},"e0498769-971e-49e2-8041-a720250a54b9":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"aha-sk-64-CHARACTER-RANDOM-STRING","description":"API key for authentication. Non-empty Security Requirement values are\nAhaSend API-key roles. Roles listed within one requirement object are\njointly required; separate requirement objects are alternatives.\n","scopes":["messages:send:{domain}"],"schemeName":"BearerAuth"}}},"servers":{"86d7498e-4af6-401e-8ea8-8da69eeecaa7":{"url":"https://api.ahasend.com","description":"Production server"}},"processedSecurityOptions":[{"schemes":[{"scheme":{"type":"http","scheme":"bearer","bearerFormat":"aha-sk-64-CHARACTER-RANDOM-STRING","description":"API key for authentication. Non-empty Security Requirement values are\nAhaSend API-key roles. Roles listed within one requirement object are\njointly required; separate requirement objects are alternatives.\n","scopes":["messages:send:all"],"schemeName":"BearerAuth"},"schema":{"title":"Bearer Auth","type":"string","isRequired":true,"description":"API key for authentication. Non-empty Security Requirement values are\nAhaSend API-key roles. Roles listed within one requirement object are\njointly required; separate requirement objects are alternatives.\n","format":"bearer","typeLabel":"string\u003cbearer>","deprecated":false},"schemeName":"BearerAuth","name":"Authorization"}],"title":"BearerAuth"},{"schemes":[{"scheme":{"type":"http","scheme":"bearer","bearerFormat":"aha-sk-64-CHARACTER-RANDOM-STRING","description":"API key for authentication. Non-empty Security Requirement values are\nAhaSend API-key roles. Roles listed within one requirement object are\njointly required; separate requirement objects are alternatives.\n","scopes":["messages:send:{domain}"],"schemeName":"BearerAuth"},"schema":{"title":"Bearer Auth","type":"string","isRequired":true,"description":"API key for authentication. Non-empty Security Requirement values are\nAhaSend API-key roles. Roles listed within one requirement object are\njointly required; separate requirement objects are alternatives.\n","format":"bearer","typeLabel":"string\u003cbearer>","deprecated":false},"schemeName":"BearerAuth","name":"Authorization"}],"title":"BearerAuth"}]},"originalFileLocation":"openapi.yaml"},"subdomain":"ahasend","siteName":"AhaSend","title":"Send an Email via the API - AhaSend","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-10-19T12:46:57.958Z","originalFileLocation":"api-reference/messages/create-message.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Send transactional email with the AhaSend API v2: one POST request to up to 100 recipients with templates, attachments, tracking, tags and scheduled sending.\">\u003cmeta data-mint-head name=\"application-name\" content=\"AhaSend\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/docs/mintlify-assets/_mintlify/favicons/ahasend/4BjAcdwrGYDKJCaO/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/docs/mintlify-assets/_mintlify/favicons/ahasend/4BjAcdwrGYDKJCaO/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/docs/mintlify-assets/_mintlify/favicons/ahasend/4BjAcdwrGYDKJCaO/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/docs/mintlify-assets/_mintlify/favicons/ahasend/4BjAcdwrGYDKJCaO/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/docs/mintlify-assets/_mintlify/favicons/ahasend/4BjAcdwrGYDKJCaO/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/docs/mintlify-assets/_mintlify/favicons/ahasend/4BjAcdwrGYDKJCaO/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/docs/mintlify-assets/_mintlify/favicons/ahasend/4BjAcdwrGYDKJCaO/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/docs/mintlify-assets/_mintlify/favicons/ahasend/4BjAcdwrGYDKJCaO/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/docs/mintlify-assets/_mintlify/favicons/ahasend/4BjAcdwrGYDKJCaO/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Send an Email via the API - AhaSend\">\u003cmeta data-mint-head property=\"og:description\" content=\"Send transactional email with the AhaSend API v2: one POST request to up to 100 recipients with templates, attachments, tracking, tags and scheduled sending.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"AhaSend\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://ahasend.com/docs/api-reference/messages/create-message\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://ahasend.mintlify.app/_mintlify/api/og/v2?division=Messages\u0026amp;title=Send+an+Email+via+the+API\u0026amp;description=Send+transactional+email+with+the+AhaSend+API+v2%3A+one+POST+request+to+up+to+100+recipients+with+templates%2C+attachments%2C+tracking%2C+tags+and+scheduled+sending.\u0026amp;theme=fec911c84bb9f722051c4af3\u0026amp;signature=ccf843a6b5bc316bb36be707eb8a86b62e8c607aaff165b873e14f51cfdfe55c\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Send an Email via the API - AhaSend\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Send transactional email with the AhaSend API v2: one POST request to up to 100 recipients with templates, attachments, tracking, tags and scheduled sending.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://ahasend.mintlify.app/_mintlify/api/og/v2?division=Messages\u0026amp;title=Send+an+Email+via+the+API\u0026amp;description=Send+transactional+email+with+the+AhaSend+API+v2%3A+one+POST+request+to+up+to+100+recipients+with+templates%2C+attachments%2C+tracking%2C+tags+and+scheduled+sending.\u0026amp;theme=fec911c84bb9f722051c4af3\u0026amp;signature=ccf843a6b5bc316bb36be707eb8a86b62e8c607aaff165b873e14f51cfdfe55c\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/docs/mintlify-assets/_mintlify/favicons/ahasend/4BjAcdwrGYDKJCaO/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"AhaSend\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#066fd1\">\u003clink data-mint-head rel=\"canonical\" href=\"https://ahasend.com/docs/api-reference/messages/create-message\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/docs/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/docs/api-reference/messages/create-message.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://ahasend.com/#organization\",\"name\":\"AhaSend\",\"legalName\":\"AhaSend B.V.\",\"url\":\"https://ahasend.com\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/ahasend/F35Ozd-1GsftDpcH/logo.png?fit=max\u0026auto=format\u0026n=F35Ozd-1GsftDpcH\u0026q=85\u0026s=ca1d4c27f7c2811598e65cb25a21323c\"},\"sameAs\":[\"https://x.com/aha_send\",\"https://www.linkedin.com/company/ahasend\",\"https://github.com/ahasend\"]},{\"@type\":\"WebSite\",\"@id\":\"https://ahasend.com/docs#website\",\"name\":\"AhaSend\",\"url\":\"https://ahasend.com/docs\",\"publisher\":{\"@id\":\"https://ahasend.com/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://ahasend.com/docs/api-reference/messages/create-message#webpage\",\"url\":\"https://ahasend.com/docs/api-reference/messages/create-message\",\"name\":\"Send an Email via the API\",\"description\":\"Send transactional email with the AhaSend API v2: one POST request to up to 100 recipients with templates, attachments, tracking, tags and scheduled sending.\",\"dateModified\":\"2026-10-19T12:46:57.958Z\",\"isPartOf\":{\"@id\":\"https://ahasend.com/docs#website\"},\"breadcrumb\":{\"@id\":\"https://ahasend.com/docs/api-reference/messages/create-message#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://ahasend.com/docs/api-reference/messages/create-message#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"AhaSend\",\"item\":\"https://ahasend.com/docs\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Send an Email via the API\",\"item\":\"https://ahasend.com/docs/api-reference/messages/create-message\"}]},{\"@type\":[\"TechArticle\",\"APIReference\"],\"@id\":\"https://ahasend.com/docs/api-reference/messages/create-message#apireference\",\"headline\":\"Send an Email via the API\",\"name\":\"Send an Email via the API\",\"description\":\"Send transactional email with the AhaSend API v2: one POST request to up to 100 recipients with templates, attachments, tracking, tags and scheduled sending.\",\"url\":\"https://ahasend.com/docs/api-reference/messages/create-message\",\"mainEntityOfPage\":{\"@id\":\"https://ahasend.com/docs/api-reference/messages/create-message#webpage\"},\"dateModified\":\"2026-10-19T12:46:57.958Z\",\"publisher\":{\"@id\":\"https://ahasend.com/#organization\"},\"isPartOf\":{\"@id\":\"https://ahasend.com/docs#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"AhaSend\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"AhaSend","nav":{"global":null,"tabs":[{"tab":"Documentation","icon":"book-open","pages":[{"title":"Documentation","href":""}]},{"tab":"API Reference","icon":"code","groups":[{"group":"Overview","pages":[{"title":"Email API Reference (v2)","sidebarTitle":"Introduction","icon":"book","href":"/api-reference"},{"title":"API Authentication with Bearer API Keys","sidebarTitle":"Authentication","icon":"key","href":"/api-reference/authentication"},{"title":"API Key Scopes and Permissions","sidebarTitle":"Scopes","icon":"lock","href":"/api-reference/scopes"},{"title":"API Rate Limits and 429 Handling","sidebarTitle":"Rate Limits","icon":"gauge-high","href":"/api-reference/rate-limits"},{"title":"Idempotency Keys for Safe API Retries","icon":"repeat","sidebarTitle":"Idempotency","href":"/api-reference/idempotency"},{"title":"API Error Codes and Error Responses","description":"Reference for AhaSend API v2 HTTP status codes (400, 401, 403, 404, 409, 422, 429, 500, 502, 503), the JSON error format, example messages and fixes for each.","icon":"triangle-exclamation","sidebarTitle":"Errors","href":"/api-reference/errors"}]},{"group":"API reference","pages":[{"group":"Messages","icon":"envelope","pages":[{"title":"Send an Email via the API","sidebarTitle":"Create Message","openapi":"openapi.yaml POST /v2/accounts/{account_id}/messages","href":"/api-reference/messages/create-message"},{"title":"Send a Transactional Template via the API","sidebarTitle":"Create Template Message","openapi":"openapi.yaml POST /v2/accounts/{account_id}/messages/template","description":"Send a published AhaSend transactional template by its ID to up to 100 recipients. Each recipient gives its own values for the template's variables.","href":"/api-reference/messages/create-template-message"},{"title":"Send Email with CC and BCC via the API","sidebarTitle":"Create Conversation","openapi":"openapi.yaml POST /v2/accounts/{account_id}/messages/conversation","href":"/api-reference/messages/create-conversation"},{"title":"Get a Message by ID via the API","sidebarTitle":"Get Message","openapi":"openapi.yaml GET /v2/accounts/{account_id}/messages/{message_id}","href":"/api-reference/messages/get-message"},{"title":"List and Search Sent Emails via the API","sidebarTitle":"List Messages","openapi":"openapi.yaml GET /v2/accounts/{account_id}/messages","href":"/api-reference/messages/get-messages"},{"title":"Cancel a Scheduled Email via the API","sidebarTitle":"Cancel Message","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/messages/{message_id}/cancel","href":"/api-reference/messages/cancel-message"}]},{"group":"Transactional Templates","icon":"file-lines","pages":[{"title":"Create a Transactional Template via the API","sidebarTitle":"Create Template","openapi":"openapi.yaml POST /v2/accounts/{account_id}/templates","href":"/api-reference/templates/create-template"},{"title":"Get a Transactional Template via the API","sidebarTitle":"Get Template","openapi":"openapi.yaml GET /v2/accounts/{account_id}/templates/{template_id}","href":"/api-reference/templates/get-template"},{"title":"Get a Published Transactional Template via the API","sidebarTitle":"Get Published Template","openapi":"openapi.yaml GET /v2/accounts/{account_id}/templates/{template_id}/published","href":"/api-reference/templates/get-published-template"},{"title":"List Transactional Templates via the API","sidebarTitle":"List Templates","openapi":"openapi.yaml GET /v2/accounts/{account_id}/templates","href":"/api-reference/templates/get-templates"},{"title":"Update a Transactional Template via the API","sidebarTitle":"Update Template","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/templates/{template_id}","href":"/api-reference/templates/update-template"},{"title":"Publish a Template Draft via the API","sidebarTitle":"Publish Template","openapi":"openapi.yaml POST /v2/accounts/{account_id}/templates/{template_id}/publish","href":"/api-reference/templates/publish-template"},{"title":"Discard a Template Draft via the API","sidebarTitle":"Discard Template Draft","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/templates/{template_id}/draft","href":"/api-reference/templates/discard-template-draft"},{"title":"List Template Versions via the API","sidebarTitle":"List Template Versions","openapi":"openapi.yaml GET /v2/accounts/{account_id}/templates/{template_id}/versions","href":"/api-reference/templates/get-template-versions"},{"title":"Get a Template Version via the API","sidebarTitle":"Get Template Version","openapi":"openapi.yaml GET /v2/accounts/{account_id}/templates/{template_id}/versions/{version_id}","href":"/api-reference/templates/get-template-version"},{"title":"Restore a Template Version via the API","sidebarTitle":"Restore Template Version","openapi":"openapi.yaml POST /v2/accounts/{account_id}/templates/{template_id}/versions/{version_id}/restore","href":"/api-reference/templates/restore-template-version"},{"title":"Delete a Transactional Template via the API","sidebarTitle":"Delete Template","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/templates/{template_id}","href":"/api-reference/templates/delete-template"}]},{"group":"Campaigns","icon":"bullhorn","pages":[{"title":"Campaigns API Overview","sidebarTitle":"Introduction","icon":"bullhorn","href":"/api-reference/campaigns/overview"},{"title":"Create a Campaign via the API","sidebarTitle":"Create Campaign","openapi":"openapi.yaml POST /v2/accounts/{account_id}/campaigns","href":"/api-reference/campaigns/create-campaign"},{"title":"Get a Campaign via the API","sidebarTitle":"Get Campaign","openapi":"openapi.yaml GET /v2/accounts/{account_id}/campaigns/{campaign_id}","href":"/api-reference/campaigns/get-campaign"},{"title":"List Campaigns via the API","sidebarTitle":"List Campaigns","openapi":"openapi.yaml GET /v2/accounts/{account_id}/campaigns","href":"/api-reference/campaigns/get-campaigns"},{"title":"Update a Campaign via the API","sidebarTitle":"Update Campaign","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/campaigns/{campaign_id}","href":"/api-reference/campaigns/update-campaign"},{"title":"Duplicate a Campaign via the API","sidebarTitle":"Duplicate Campaign","openapi":"openapi.yaml POST /v2/accounts/{account_id}/campaigns/{campaign_id}/duplicate","href":"/api-reference/campaigns/duplicate-campaign"},{"title":"Send a Campaign Test via the API","sidebarTitle":"Test Campaign","openapi":"openapi.yaml POST /v2/accounts/{account_id}/campaigns/{campaign_id}/test","href":"/api-reference/campaigns/test-campaign"},{"title":"Send or Schedule a Campaign via the API","sidebarTitle":"Send Campaign","openapi":"openapi.yaml POST /v2/accounts/{account_id}/campaigns/{campaign_id}/send","href":"/api-reference/campaigns/send-campaign"},{"title":"Unschedule a Campaign via the API","sidebarTitle":"Unschedule Campaign","openapi":"openapi.yaml POST /v2/accounts/{account_id}/campaigns/{campaign_id}/unschedule","href":"/api-reference/campaigns/unschedule-campaign"},{"title":"Get Campaign Stats via the API","sidebarTitle":"Get Campaign Stats","openapi":"openapi.yaml GET /v2/accounts/{account_id}/campaigns/{campaign_id}/stats","href":"/api-reference/campaigns/get-campaign-stats"},{"title":"List Campaign Recipients via the API","sidebarTitle":"List Campaign Recipients","openapi":"openapi.yaml GET /v2/accounts/{account_id}/campaigns/{campaign_id}/recipients","href":"/api-reference/campaigns/get-campaign-recipients"},{"title":"Delete a Campaign via the API","sidebarTitle":"Delete Campaign","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/campaigns/{campaign_id}","href":"/api-reference/campaigns/delete-campaign"}]},{"group":"Campaign Templates","icon":"palette","pages":[{"title":"Create a Campaign Template via the API","sidebarTitle":"Create Template","openapi":"openapi.yaml POST /v2/accounts/{account_id}/campaign-templates","href":"/api-reference/campaign-templates/create-campaign-template"},{"title":"Get a Campaign Template via the API","sidebarTitle":"Get Template","openapi":"openapi.yaml GET /v2/accounts/{account_id}/campaign-templates/{template_id}","href":"/api-reference/campaign-templates/get-campaign-template"},{"title":"List Campaign Templates via the API","sidebarTitle":"List Templates","openapi":"openapi.yaml GET /v2/accounts/{account_id}/campaign-templates","href":"/api-reference/campaign-templates/get-campaign-templates"},{"title":"Update a Campaign Template via the API","sidebarTitle":"Update Template","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/campaign-templates/{template_id}","href":"/api-reference/campaign-templates/update-campaign-template"},{"title":"Delete a Campaign Template via the API","sidebarTitle":"Delete Template","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/campaign-templates/{template_id}","href":"/api-reference/campaign-templates/delete-campaign-template"}]},{"group":"Contacts","icon":"address-book","pages":[{"title":"Contacts API Overview","sidebarTitle":"Introduction","icon":"address-book","href":"/api-reference/contacts/overview"},{"title":"Create a Contact via the API","sidebarTitle":"Create Contact","openapi":"openapi.yaml POST /v2/accounts/{account_id}/contacts","href":"/api-reference/contacts/create-contact"},{"title":"Get a Contact via the API","sidebarTitle":"Get Contact","openapi":"openapi.yaml GET /v2/accounts/{account_id}/contacts/{id_or_email}","href":"/api-reference/contacts/get-contact"},{"title":"List Contacts via the API","sidebarTitle":"List Contacts","openapi":"openapi.yaml GET /v2/accounts/{account_id}/contacts","href":"/api-reference/contacts/get-contacts"},{"title":"Update a Contact via the API","sidebarTitle":"Update Contact","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/contacts/{id_or_email}","href":"/api-reference/contacts/update-contact"},{"title":"Delete a Contact via the API","sidebarTitle":"Delete Contact","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/contacts/{id_or_email}","href":"/api-reference/contacts/delete-contact"},{"title":"Create or Update Contacts in a Batch via the API","sidebarTitle":"Batch Upsert Contacts","openapi":"openapi.yaml POST /v2/accounts/{account_id}/contacts/batch","href":"/api-reference/contacts/batch-upsert-contacts"}]},{"group":"Lists","icon":"list-ul","pages":[{"title":"Lists API Overview","sidebarTitle":"Introduction","icon":"list-ul","href":"/api-reference/lists/overview"},{"title":"Create a List via the API","sidebarTitle":"Create List","openapi":"openapi.yaml POST /v2/accounts/{account_id}/lists","href":"/api-reference/lists/create-list"},{"title":"Get a List via the API","sidebarTitle":"Get List","openapi":"openapi.yaml GET /v2/accounts/{account_id}/lists/{list_id}","href":"/api-reference/lists/get-list"},{"title":"List Contact Lists via the API","sidebarTitle":"List Lists","openapi":"openapi.yaml GET /v2/accounts/{account_id}/lists","href":"/api-reference/lists/get-lists"},{"title":"Update a List via the API","sidebarTitle":"Update List","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/lists/{list_id}","href":"/api-reference/lists/update-list"},{"title":"Delete a List via the API","sidebarTitle":"Delete List","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/lists/{list_id}","href":"/api-reference/lists/delete-list"},{"title":"List the Contacts on a List via the API","sidebarTitle":"List Contacts on a List","openapi":"openapi.yaml GET /v2/accounts/{account_id}/lists/{list_id}/contacts","href":"/api-reference/lists/get-list-contacts"},{"title":"Add or Update a List Contact via the API","sidebarTitle":"Add or Update List Contact","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/lists/{list_id}/contacts/{id_or_email}","href":"/api-reference/lists/upsert-list-contact"},{"title":"Add Contacts to a List in a Batch via the API","sidebarTitle":"Batch Add List Contacts","openapi":"openapi.yaml POST /v2/accounts/{account_id}/lists/{list_id}/contacts/batch","href":"/api-reference/lists/batch-add-list-contacts"},{"title":"Remove a Contact from a List via the API","sidebarTitle":"Remove List Contact","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/lists/{list_id}/contacts/{id_or_email}","href":"/api-reference/lists/delete-list-contact"},{"title":"List a Contact's Lists via the API","sidebarTitle":"List Contact's Lists","openapi":"openapi.yaml GET /v2/accounts/{account_id}/contacts/{id_or_email}/lists","href":"/api-reference/lists/get-contact-lists"}]},{"group":"Segments","icon":"filter","pages":[{"title":"Segments API Overview","sidebarTitle":"Introduction","icon":"filter","href":"/api-reference/segments/overview"},{"title":"Preview a Segment via the API","sidebarTitle":"Preview Segment","openapi":"openapi.yaml POST /v2/accounts/{account_id}/segments/preview","href":"/api-reference/segments/preview-segment"},{"title":"Create a Segment via the API","sidebarTitle":"Create Segment","openapi":"openapi.yaml POST /v2/accounts/{account_id}/segments","href":"/api-reference/segments/create-segment"},{"title":"Get a Segment via the API","sidebarTitle":"Get Segment","openapi":"openapi.yaml GET /v2/accounts/{account_id}/segments/{segment_id}","href":"/api-reference/segments/get-segment"},{"title":"List Segments via the API","sidebarTitle":"List Segments","openapi":"openapi.yaml GET /v2/accounts/{account_id}/segments","href":"/api-reference/segments/get-segments"},{"title":"Update a Segment via the API","sidebarTitle":"Update Segment","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/segments/{segment_id}","href":"/api-reference/segments/update-segment"},{"title":"Delete a Segment via the API","sidebarTitle":"Delete Segment","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/segments/{segment_id}","href":"/api-reference/segments/delete-segment"},{"title":"List the Contacts in a Segment via the API","sidebarTitle":"List Segment Contacts","openapi":"openapi.yaml GET /v2/accounts/{account_id}/segments/{segment_id}/contacts","href":"/api-reference/segments/get-segment-contacts"},{"title":"List a Contact's Segments via the API","sidebarTitle":"List Contact's Segments","openapi":"openapi.yaml GET /v2/accounts/{account_id}/contacts/{id_or_email}/segments","href":"/api-reference/segments/get-contact-segments"}]},{"group":"Suppressions","icon":"ban","pages":[{"title":"Add an Address to the Suppression List via the API","sidebarTitle":"Create Suppression","openapi":"openapi.yaml POST /v2/accounts/{account_id}/suppressions","href":"/api-reference/suppressions/create-suppression"},{"title":"List Suppressed Addresses via the API","sidebarTitle":"List Suppressions","openapi":"openapi.yaml GET /v2/accounts/{account_id}/suppressions","href":"/api-reference/suppressions/get-suppressions"},{"title":"Remove a Suppression via the API","sidebarTitle":"Delete Suppression","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/suppressions","href":"/api-reference/suppressions/delete-suppression"},{"title":"Delete All Suppressions via the API","sidebarTitle":"Delete All Suppressions","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/suppressions/all","href":"/api-reference/suppressions/wipe-suppressions"}]},{"group":"SMTP Credentials","icon":"user-shield","pages":[{"title":"Create SMTP Credentials via the API","sidebarTitle":"Create SMTP Credential","openapi":"openapi.yaml POST /v2/accounts/{account_id}/smtp-credentials","href":"/api-reference/smtp-credentials/create-smtp-credential"},{"title":"Get an SMTP Credential via the API","sidebarTitle":"Get SMTP Credential","openapi":"openapi.yaml GET /v2/accounts/{account_id}/smtp-credentials/{smtp_credential_id}","href":"/api-reference/smtp-credentials/get-smtp-credential"},{"title":"List SMTP Credentials via the API","sidebarTitle":"List SMTP Credentials","openapi":"openapi.yaml GET /v2/accounts/{account_id}/smtp-credentials","href":"/api-reference/smtp-credentials/get-smtp-credentials"},{"title":"Delete an SMTP Credential via the API","sidebarTitle":"Delete SMTP Credential","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/smtp-credentials/{smtp_credential_id}","href":"/api-reference/smtp-credentials/delete-smtp-credential"}]},{"group":"Webhooks","icon":"webhook","pages":[{"title":"Create a Webhook via the API","sidebarTitle":"Create Webhook","openapi":"openapi.yaml POST /v2/accounts/{account_id}/webhooks","href":"/api-reference/webhooks/create-webhook"},{"title":"Get a Webhook via the API","sidebarTitle":"Get Webhook","openapi":"openapi.yaml GET /v2/accounts/{account_id}/webhooks/{webhook_id}","href":"/api-reference/webhooks/get-webhook"},{"title":"List Webhooks via the API","sidebarTitle":"List Webhooks","openapi":"openapi.yaml GET /v2/accounts/{account_id}/webhooks","href":"/api-reference/webhooks/get-webhooks"},{"title":"Update a Webhook via the API","sidebarTitle":"Update Webhook","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/webhooks/{webhook_id}","href":"/api-reference/webhooks/update-webhook"},{"title":"Delete a Webhook via the API","sidebarTitle":"Delete Webhook","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/webhooks/{webhook_id}","href":"/api-reference/webhooks/delete-webhook"}]},{"group":"Routes","icon":"route","pages":[{"title":"Create an Inbound Email Route via the API","sidebarTitle":"Create Route","openapi":"openapi.yaml POST /v2/accounts/{account_id}/routes","href":"/api-reference/routes/create-route"},{"title":"Get an Inbound Email Route via the API","sidebarTitle":"Get Route","openapi":"openapi.yaml GET /v2/accounts/{account_id}/routes/{route_id}","href":"/api-reference/routes/get-route"},{"title":"List Inbound Email Routes via the API","sidebarTitle":"List Routes","openapi":"openapi.yaml GET /v2/accounts/{account_id}/routes","href":"/api-reference/routes/get-routes"},{"title":"Update an Inbound Email Route via the API","sidebarTitle":"Update Route","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/routes/{route_id}","href":"/api-reference/routes/update-route"},{"title":"Delete an Inbound Email Route via the API","sidebarTitle":"Delete Route","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/routes/{route_id}","href":"/api-reference/routes/delete-route"}]},{"group":"Domains","icon":"globe","pages":[{"title":"Add a Sending Domain via the API","sidebarTitle":"Create Domain","openapi":"openapi.yaml POST /v2/accounts/{account_id}/domains","href":"/api-reference/domains/create-domain"},{"title":"Get a Domain and Its DNS Records via the API","sidebarTitle":"Get Domain","openapi":"openapi.yaml GET /v2/accounts/{account_id}/domains/{domain}","href":"/api-reference/domains/get-domain"},{"title":"List Sending Domains via the API","sidebarTitle":"List Domains","openapi":"openapi.yaml GET /v2/accounts/{account_id}/domains","href":"/api-reference/domains/get-domains"},{"title":"Update a Sending Domain via the API","sidebarTitle":"Update Domain","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/domains/{domain}","href":"/api-reference/domains/update-domain"},{"title":"Check Domain DNS Records via the API","sidebarTitle":"Check Domain DNS","openapi":"openapi.yaml POST /v2/accounts/{account_id}/domains/{domain}/check-dns","href":"/api-reference/domains/check-dns"},{"title":"Delete a Sending Domain via the API","sidebarTitle":"Delete Domain","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/domains/{domain}","href":"/api-reference/domains/delete-domain"}]},{"group":"Accounts","icon":"building","pages":[{"title":"Get Account Details via the API","sidebarTitle":"Get Account","openapi":"openapi.yaml GET /v2/accounts/{account_id}","href":"/api-reference/accounts/get-account"},{"title":"Update Account Settings via the API","sidebarTitle":"Update Account","openapi":"openapi.yaml PUT /v2/accounts/{account_id}","href":"/api-reference/accounts/update-account"},{"title":"List Account Members via the API","sidebarTitle":"List Account Members","openapi":"openapi.yaml GET /v2/accounts/{account_id}/members","href":"/api-reference/accounts/get-account-members"},{"title":"Add an Account Member via the API","sidebarTitle":"Add Account Member","openapi":"openapi.yaml POST /v2/accounts/{account_id}/members","href":"/api-reference/accounts/create-account-member"},{"title":"Remove an Account Member via the API","sidebarTitle":"Remove Account Member","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/members/{user_id}","href":"/api-reference/accounts/delete-account-member"}]},{"group":"Sub-Accounts","icon":"sitemap","pages":[{"title":"Sub-Accounts API Overview","sidebarTitle":"Introduction","icon":"sitemap","href":"/api-reference/sub-accounts/overview"},{"title":"Create a Sub-Account via the API","sidebarTitle":"Create Sub-Account","openapi":"openapi.yaml POST /v2/accounts/{account_id}/sub-accounts","href":"/api-reference/sub-accounts/create-sub-account"},{"title":"List Sub-Accounts via the API","sidebarTitle":"List Sub-Accounts","openapi":"openapi.yaml GET /v2/accounts/{account_id}/sub-accounts","href":"/api-reference/sub-accounts/get-sub-accounts"},{"title":"Get a Sub-Account via the API","sidebarTitle":"Get Sub-Account","openapi":"openapi.yaml GET /v2/accounts/{account_id}/sub-accounts/{sub_account_id}","href":"/api-reference/sub-accounts/get-sub-account"},{"title":"Update a Sub-Account via the API","sidebarTitle":"Update Sub-Account","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/sub-accounts/{sub_account_id}","href":"/api-reference/sub-accounts/update-sub-account"},{"title":"Pause a Sub-Account via the API","sidebarTitle":"Pause Sub-Account","openapi":"openapi.yaml POST /v2/accounts/{account_id}/sub-accounts/{sub_account_id}/suspend","href":"/api-reference/sub-accounts/suspend-sub-account"},{"title":"Resume a Sub-Account via the API","sidebarTitle":"Resume Sub-Account","openapi":"openapi.yaml POST /v2/accounts/{account_id}/sub-accounts/{sub_account_id}/unsuspend","href":"/api-reference/sub-accounts/unsuspend-sub-account"},{"title":"Unpause a Sub-Account Domain via the API","sidebarTitle":"Unpause Sub-Account Domain","openapi":"openapi.yaml POST /v2/accounts/{account_id}/sub-accounts/{sub_account_id}/domains/{domain}/unpause","href":"/api-reference/sub-accounts/unpause-sub-account-domain"},{"title":"Delete a Sub-Account via the API","sidebarTitle":"Delete Sub-Account","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/sub-accounts/{sub_account_id}","href":"/api-reference/sub-accounts/delete-sub-account"},{"title":"Get Sub-Account Usage via the API","sidebarTitle":"Sub-Account Usage","openapi":"openapi.yaml GET /v2/accounts/{account_id}/sub-accounts/usage","href":"/api-reference/sub-accounts/get-sub-accounts-usage"}]},{"group":"Sub-Account API Keys","icon":"key","pages":[{"title":"Create a Sub-Account API Key via the API","sidebarTitle":"Create API Key","openapi":"openapi.yaml POST /v2/accounts/{account_id}/sub-accounts/{sub_account_id}/api-keys","href":"/api-reference/sub-accounts/create-sub-account-api-key"},{"title":"Get a Sub-Account API Key via the API","sidebarTitle":"Get API Key","openapi":"openapi.yaml GET /v2/accounts/{account_id}/sub-accounts/{sub_account_id}/api-keys/{key_id}","href":"/api-reference/sub-accounts/get-sub-account-api-key"},{"title":"List Sub-Account API Keys via the API","sidebarTitle":"List API Keys","openapi":"openapi.yaml GET /v2/accounts/{account_id}/sub-accounts/{sub_account_id}/api-keys","href":"/api-reference/sub-accounts/get-sub-account-api-keys"},{"title":"Update a Sub-Account API Key via the API","sidebarTitle":"Update API Key","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/sub-accounts/{sub_account_id}/api-keys/{key_id}","href":"/api-reference/sub-accounts/update-sub-account-api-key"},{"title":"Delete a Sub-Account API Key via the API","sidebarTitle":"Delete API Key","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/sub-accounts/{sub_account_id}/api-keys/{key_id}","href":"/api-reference/sub-accounts/delete-sub-account-api-key"}]},{"group":"Reports","icon":"chart-line","pages":[{"title":"Get Email Deliverability Statistics via the API","sidebarTitle":"Deliverability Report","openapi":"openapi.yaml GET /v2/accounts/{account_id}/statistics/transactional/deliverability","href":"/api-reference/reports/get-deliverability-report"},{"title":"Get Email Bounce Statistics via the API","sidebarTitle":"Bounce Report","openapi":"openapi.yaml GET /v2/accounts/{account_id}/statistics/transactional/bounce","href":"/api-reference/reports/get-bounce-report"},{"title":"Get Email Delivery Time Statistics via the API","sidebarTitle":"Delivery Time Report","openapi":"openapi.yaml GET /v2/accounts/{account_id}/statistics/transactional/delivery-time","href":"/api-reference/reports/get-delivery-time-report"}]},{"group":"API Keys","icon":"key","pages":[{"title":"Create an API Key via the API","sidebarTitle":"Create API Key","openapi":"openapi.yaml POST /v2/accounts/{account_id}/api-keys","href":"/api-reference/api-keys/create-api-key"},{"title":"Get an API Key via the API","sidebarTitle":"Get API Key","openapi":"openapi.yaml GET /v2/accounts/{account_id}/api-keys/{key_id}","href":"/api-reference/api-keys/get-api-key"},{"title":"List API Keys via the API","sidebarTitle":"List API Keys","openapi":"openapi.yaml GET /v2/accounts/{account_id}/api-keys","href":"/api-reference/api-keys/get-api-keys"},{"title":"Update an API Key via the API","sidebarTitle":"Update API Key","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/api-keys/{key_id}","href":"/api-reference/api-keys/update-api-key"},{"title":"Delete an API Key via the API","sidebarTitle":"Delete API Key","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/api-keys/{key_id}","href":"/api-reference/api-keys/delete-api-key"}]},{"group":"Utility endpoints","icon":"bolt","pages":[{"title":"Test Your API Key with the Ping Endpoint","sidebarTitle":"Ping","openapi":"openapi.yaml GET /v2/ping","href":"/api-reference/utility/ping"}]}]},{"group":"Webhooks","pages":[{"title":"Webhook Events and Payload Reference","sidebarTitle":"Introduction","icon":"webhook","href":"/api-reference/webhooks/index"},{"title":"Verify Webhook and Route Signatures (HMAC)","sidebarTitle":"Security","icon":"shield-check","href":"/api-reference/webhooks/security"},{"title":"Webhook and Route Retry Policy","sidebarTitle":"Retry Policy","icon":"repeat","href":"/api-reference/webhooks/retry-policy"},{"group":"Message Events","icon":"envelope","pages":[{"title":"message.reception Webhook Event","sidebarTitle":"Reception","openapi":"webhooks.yaml webhook message.reception","href":"/api-reference/webhooks/message-reception"},{"title":"message.delivered Webhook Event","sidebarTitle":"Delivered","openapi":"webhooks.yaml webhook message.delivered","href":"/api-reference/webhooks/message-delivered"},{"title":"message.transient_error (Deferred) Webhook Event","sidebarTitle":"Deferred","openapi":"webhooks.yaml webhook message.transient_error","href":"/api-reference/webhooks/message-transient_error"},{"title":"message.failed Webhook Event","sidebarTitle":"Failed","openapi":"webhooks.yaml webhook message.failed","href":"/api-reference/webhooks/message-failed"},{"title":"message.bounced Webhook Event","sidebarTitle":"Bounced","openapi":"webhooks.yaml webhook message.bounced","href":"/api-reference/webhooks/message-bounced"},{"title":"message.suppressed Webhook Event","sidebarTitle":"Suppressed","openapi":"webhooks.yaml webhook message.suppressed","href":"/api-reference/webhooks/message-suppressed"},{"title":"message.opened Webhook Event","sidebarTitle":"Opened","openapi":"webhooks.yaml webhook message.opened","href":"/api-reference/webhooks/message-opened"},{"title":"message.clicked Webhook Event","sidebarTitle":"Clicked","openapi":"webhooks.yaml webhook message.clicked","href":"/api-reference/webhooks/message-clicked"},{"title":"message.unsubscribed Webhook Event","sidebarTitle":"Unsubscribed","openapi":"webhooks.yaml webhook message.unsubscribed","href":"/api-reference/webhooks/message-unsubscribed"},{"title":"message.complained Webhook Event","sidebarTitle":"Complained","openapi":"webhooks.yaml webhook message.complained","href":"/api-reference/webhooks/message-complained"}]},{"group":"Suppression Events","icon":"ban","pages":[{"title":"suppression.created Webhook Event","sidebarTitle":"Suppression Created","openapi":"webhooks.yaml webhook suppression.created","href":"/api-reference/webhooks/suppression-created"},{"title":"suppression.deleted Webhook Event","sidebarTitle":"Suppression Deleted","openapi":"webhooks.yaml webhook suppression.deleted","href":"/api-reference/webhooks/suppression-deleted"}]},{"group":"Domain Events","icon":"globe","pages":[{"title":"domain.dns_error Webhook Event","sidebarTitle":"DNS Error","openapi":"webhooks.yaml webhook domain.dns_error","href":"/api-reference/webhooks/domain-dns_error"}]},{"group":"Contact Events","icon":"address-book","pages":[{"title":"contact.created Webhook Event","sidebarTitle":"Contact Created","openapi":"webhooks.yaml webhook contact.created","href":"/api-reference/webhooks/contact-created"},{"title":"contact.updated Webhook Event","sidebarTitle":"Contact Updated","openapi":"webhooks.yaml webhook contact.updated","href":"/api-reference/webhooks/contact-updated"},{"title":"contact.deleted Webhook Event","sidebarTitle":"Contact Deleted","openapi":"webhooks.yaml webhook contact.deleted","href":"/api-reference/webhooks/contact-deleted"},{"title":"contact.added_to_list Webhook Event","sidebarTitle":"Contact Added to List","openapi":"webhooks.yaml webhook contact.added_to_list","href":"/api-reference/webhooks/contact-added_to_list"},{"title":"contact.removed_from_list Webhook Event","sidebarTitle":"Contact Removed from List","openapi":"webhooks.yaml webhook contact.removed_from_list","href":"/api-reference/webhooks/contact-removed_from_list"},{"title":"contact.subscribed Webhook Event","sidebarTitle":"Contact Subscribed","openapi":"webhooks.yaml webhook contact.subscribed","href":"/api-reference/webhooks/contact-subscribed"},{"title":"contact.unsubscribed Webhook Event","sidebarTitle":"Contact Unsubscribed","openapi":"webhooks.yaml webhook contact.unsubscribed","href":"/api-reference/webhooks/contact-unsubscribed"},{"title":"contact.complained Webhook Event","sidebarTitle":"Contact Complained","openapi":"webhooks.yaml webhook contact.complained","href":"/api-reference/webhooks/contact-complained"}]}]},{"group":"Message Routing","pages":[{"title":"Inbound Email Routing API Overview","sidebarTitle":"Introduction","icon":"route","href":"/api-reference/routes/index"},{"title":"message.routing Inbound Email Webhook Event","sidebarTitle":"Message Routing","openapi":"webhooks.yaml webhook message.routing","href":"/api-reference/routes/route-message"}]},{"group":"API v1 (legacy)","pages":[{"title":"API v1 vs v2: Differences and Migration","sidebarTitle":"v1 vs v2","icon":"code-compare","href":"/api-reference/v1/v1-vs-v2"},{"title":"Send Email with API v1 (Legacy)","sidebarTitle":"Send Email (Legacy)","icon":"paper-plane","openapi":"openapi-v1.yaml POST /v1/email/send","href":"/api-reference/v1/index"}]}]},{"tab":"CLI","icon":"square-terminal","pages":[{"title":"CLI","href":"/cli"}]},{"tab":"Guides","icon":"plug","pages":[{"title":"Guides","href":"/guides"}]},{"tab":"Changelog","icon":"clock-rotate-left","pages":[{"title":"Changelog","href":"/changelog"}]},{"tab":"Roadmap","icon":"map","pages":[{"title":"Roadmap","href":"/roadmap"}]}]},"title":"Send an Email via the API - AhaSend","buildId":"dpl_GvhK4qVXq51DpfYJLCtPpYNN4YHN","deploymentId":"dpl_GvhK4qVXq51DpfYJLCtPpYNN4YHN","dynamics":["c2aa737661","2b790eda92","b0f84f53ff","a9bb46feb3"],"chunks":["OpenApiReferenceProvider-Bg4Z7D_G.js","utils-Biz734EK.js","cloneDeep-izs3Hzxb.js","_Uint8Array-BVIqJ90l.js","isObjectLike-C8vmzPEN.js","isArray-Dcu1dQ5t.js","utils-C6F9YHs6.js","toString-BX-iyh8G.js","isSymbol-CSH9U2Gm.js","addUniqueKeysToSchema-BoJjY_VP.js","snippetPresets-CnZ-mOFh.js","style-to-object-BY3JEAdk.js","v4-DIgz8zy6.js","ApiExamples-DC_SB2pp.js","isEqual-BfaiBbcl.js","usePlaygroundInputsStore-BYKtOiIP.js","shallow-COAac_UD.js","getApiPlaygroundDisplay-BV4Viqi2.js","CodeSnippet-DDgW-JXl.js","CodeSnippets-CP1LpNhG.js","Page-BeiUfucV.js","getPastedJson-Cvgvbfmv.js","icon-D-H368xH.js","MethodPill-CXSxH1VW.js","DuplicateIcon-JcbBzF1x.js","createIcon-BDt_aHZM.js","DynamicMarkdown-DO1Fz7ar.js","SectionHeading-mwKBArs3.js","axios-vUo_bRtp.js","Markdown-C3KUTGJN.js","clsx-C6CAjViH.js","lib--scc4DXi.js","lib-B8HbPgcC.js","html-void-elements-mCSPHezU.js","dist-C3vb5JQZ.js","katex-YMM-FMeD.js","marked.esm-CZWythHk.js","AssistantPageLink-C8Hisf3g.js"]}