Back to home

SMTPDog developer documentation

Clear integration guides: domain verification, SMTP and Email API, API keys, webhook signatures and troubleshooting.

03 · email api

Email API

Integrate over standard HTTP and understand request fields, acceptance and message status.

1. Authentication and origin

Send and query with Authorization: Bearer <API Key>. Confirm the API origin and proxy prefix; never add a page locale prefix to API paths. Keep keys on the server. These are standard HTTP examples, not an SMTPDog SDK.

2. Send one message

POST /v1/mail/send accepts JSON. from and to are each a single address string, never an array. Without a template, provide a non-empty subject and at least one of text or html. cc, bcc, attachments, batch and scheduled sending fields are unsupported.

Field / settingType / statusDescription
fromstringOne sender, optionally Name <addr>; verified domain; name up to 100 characters
tostringOne recipient, not an array
subjectstringRequired without a template; no CR/LF
html / textstringAt least one non-empty body without a template. We recommend sending both html and text; a plain-text alternative can lower the chance of being filtered as spam
reply_tostringOptional single reply-to mailbox
headersmap<string,string>Optional; only List-Unsubscribe, List-Unsubscribe-Post and Auto-Submitted are allowed
template_iduint64Optional account-owned template ID
variablesmap<string,string>Optional string-valued variables
curl -X POST "${SMTPDOG_API_ORIGIN}/v1/mail/send" \
  -H "Authorization: Bearer ${SMTPDOG_API_KEY}" \
  -H "Content-Type: application/json" \
  --data '{
    "from": "sender@example.com",
    "to": "recipient@example.com",
    "subject": "Welcome to your product",
    "text": "Your message goes here."
  }'

3. Acceptance and status

A 202 response returns message_id and queued. GET /v1/mail/{message_id} returns the account-owned message status. created_at is present; delivered_at and smtp_response can be omitted. sent can mean the node accepted the message, not inbox placement or reading. Queries with a domain-scoped key are account-owned, without additional domain isolation.

Field / settingType / statusDescription
queuedstringAccepted into queue
sendingstringSubmission in progress
sentstringNode acceptance or later status; no inbox guarantee
deferredstringTemporary deferral; check later status
bouncedstringBounce
failedstringFailed sending
{
  "message_id": "00000000-0000-4000-8000-000000000000",
  "status": "queued"
}

4. Use an existing template

template_id must belong to your account. Its subject, html and text fully replace inline values before validation. variables values must be strings. {{name}} uses simple substitution; missing values retain placeholders and HTML values are escaped. Loops and conditional expressions are unsupported. Use the ID of a template you actually created.

{
  "from": "sender@example.com",
  "to": "recipient@example.com",
  "template_id": 123,
  "variables": {
    "name": "Example recipient"
  }
}

5. Errors and retries

Normal API errors contain code and error. Branch on code; error is not currently a five-language protocol. Do not repeat permission or configuration failures. A timed-out send may have been accepted. There is no idempotency-key or resend endpoint, so repetition can duplicate sends and quota usage. Failed requests are not guaranteed a quota refund.

Field / settingType / statusDescription
400 invalid_requestHTTPCheck types, subject and body
401 api_key_invalidHTTPCheck key and account status
403 domain_unverified / api_key_domain_forbidden / content_blockedHTTPCheck verification, scope and content
404 template_not_found / message_not_foundHTTPCheck resource ID and account ownership
429 quota_exceededHTTPCheck total, daily and hourly limits; avoid blind retries
500 internal_errorHTTPKeep error context and contact support; processing may be partial