Built for your next request
API reference.
SMTP2GO outbound delivery. Scoped bearer keys. Your existing receiving transport and inbox stay separate.
Your first send
Create a brand, prove ownership, and publish the exact sender records SMTP2GO returns. The ownership TXT is separate from DKIM and return-path records.
# Create a local brand. Save its id as BRAND; the name and slug can change later, the id never does.
curl -X POST https://api.mycompany.email/v1/brands \
-H "Authorization: Bearer $MYCO_API_KEY" -H "Content-Type: application/json" \
-d '{"name":"Acme","slug":"acme"}'
# Publish ownership.record directly with your DNS provider.
curl "https://api.mycompany.email/v1/domains/ownership?domain=mail.example.com&brand_id=$BRAND" \
-H "Authorization: Bearer $MYCO_API_KEY"
# Register the domain with SMTP2GO, then publish the returned dns_records.
curl -X POST https://api.mycompany.email/v1/domains \
-H "Authorization: Bearer $MYCO_API_KEY" -H "Content-Type: application/json" \
-d '{"brand_id":"'$BRAND'","domain":"mail.example.com"}'
# Save the domain id as DOMAIN. Keep ownership TXT published.
curl -X POST https://api.mycompany.email/v1/domains/$DOMAIN/check \
-H "Authorization: Bearer $MYCO_API_KEY"
# Send when ready_to_send is true.
curl -X POST https://api.mycompany.email/v1/emails \
-H "Authorization: Bearer $MYCO_API_KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: welcome-customer-8412" \
-d '{"from":"hello@mail.example.com","to":"customer@example.net",
"subject":"Welcome","text":"Your account is ready."}'Keys define access.
Workspace owners and administrators can create a key from API keys in the dashboard, and so can a member limited to some brands whose access includes API access — each of their keys stays restricted to one of those brands and, on every request, to what the member may do at that moment. Choose its permissions, optional brand restriction and expiration. Copy the key when it is created; the full value is shown only once. Revoke a key from the same page when an integration no longer needs access.
Send Authorization: Bearer YOUR_KEY on every /v1 request. Keys belong to one organization, carry operation scopes, and can be restricted to one brand. A restricted key cannot create brands, use drafts or manage members. Keep keys on trusted servers; never put them in URLs or client-side bundles.
Owners and admins can manage members from code too: /v1/members and /v1/invitations invite people to chosen brands, change their brands and permissions, and remove them. Those calls need a workspace-wide key carrying members:read or members:write, which no key gets by default. An invitation's link is returned once and never emailed by the API.
Retry the same request safely.
Supply an Idempotency-Key of 8–255 characters on mutations — except POST /v1/invitations, which refuses it so the link it returns is never stored. Successful responses and uncertain or partial provider submissions are replayed for 24 hours with Idempotent-Replay: true, preventing an ambiguous send from being submitted twice. Keep body bytes, method, path, query and API key unchanged. Mismatches return 400; an in-flight duplicate returns retryable 429. MCP is excluded.
Prove ownership before provisioning.
Fetch GET /v1/domains/ownership with domain and your brand_id. Publish the returned TXT directly at your DNS provider and keep it there. Create the domain, then publish its SMTP2GO DNS records and check until ready_to_send is true. API domain creation accepts brand_id, domain, and optional publish_dns.
Manage A, AAAA, CNAME, MX and TXT records under /v1/domains/{id}/dns/records when Cloudflare access is configured. Each operation rechecks ownership. Removing a domain unregisters it locally and retains its provider registration and DNS for separate cleanup.
Send, save, reply and forward.
Send with POST /v1/emails. HTTP 202 means provider acceptance; poll the message endpoint for delivery events. Up to 50 recipients total are allowed. Templates supply subject and body defaults. Attachment objects contain a filename and base64 bytes, with at most 20 files and 10 MiB decoded content total.
If your domain is already ready to send, use a key with email:send. Set MYCO_API_KEY in your server environment and replace the sender with an address on your verified domain and the recipient with your test address.
curl -X POST https://api.mycompany.email/v1/emails \
-H "Authorization: Bearer $MYCO_API_KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: welcome-customer-8412" \
-d '{"from":"hello@mail.example.com","to":"customer@example.net",
"subject":"Welcome","text":"Your account is ready."}'Use /v1/drafts to save incomplete text messages. Replies and forwards under /v1/inbox/{id} require both email:send and inbox:read. Replies choose the original sender or Reply-To. Forwards quote original text; attachments must be supplied explicitly.
Receiving stays on its own transport.
SMTP2GO handles outbound delivery only; incoming mail, raw archives and attachments stay on the receiving transport. A domain receives once three things hold, in order: its ownership TXT is published, its receiving identity is verified, and its MX points here. Call POST /v1/domains/{id}/receiving to record the claim and check the identity, publish any receiving.identity.dns_records it returns, then call it again. Publish receiving.mx.record last — it moves all of the domain's incoming mail.
Create an address with POST /v1/mailboxes, using domain_id and optional local_part; omit the local part for a catch-all. Mail arrives once receiving.live is true, and receiving.next_step names what is missing: ownership, identity or mx.
List or search inbox messages, download attachments, set read/star state, and move messages between folders. DELETE /v1/inbox/{id} moves mail to trash; restore returns it to inbox. Lists with pagination return the next cursor or page explicitly.
Errors say what needs to change.
JSON errors include code, message, requirement, and retryable. Respect Retry-After. Every API response includes X-Request-Id and is marked no-store; authenticated ones also report the rate-limit window in X-RateLimit-Remaining and X-RateLimit-Reset. Non-empty write bodies must be JSON; the request cap is 16 MiB including base64 expansion.
{
"error": {
"code": "domain_not_verified",
"message": "The sending domain mail.example.com is not verified",
"requirement": "verify_domain",
"reason": "Verification status is \"SMTP2GO verification pending\"",
"resolution": "Publish the DNS records from GET /v1/domains, then POST /v1/domains/:id/check",
"retryable": false
}
}Every endpoint, from the contract.
Open Swagger for exact schemas, scope requirements, pagination and response codes.
| Method | Path | Action |
|---|---|---|
POST | /v1/emails | Send an email |
GET | /v1/emails | List sent emails |
GET | /v1/emails/{id} | Read delivery status and events |
POST | /v1/brands | Create a sending brand |
GET | /v1/brands | List brands |
GET | /v1/brands/{id} | Read a sending brand |
PATCH | /v1/brands/{id} | Change a brand's name or slug |
POST | /v1/brands/{id}/provision | Activate a local brand |
POST | /v1/domains | Add and provision a sending domain |
GET | /v1/domains | List domains and DNS records |
GET | /v1/domains/{id} | Read a domain's DNS and verification status |
DELETE | /v1/domains/{id} | Unregister a sending domain |
POST | /v1/domains/{id}/provision | Retry domain provisioning |
POST | /v1/domains/{id}/check | Refresh domain verification |
POST | /v1/domains/{id}/publish-dns | Publish DNS records to Cloudflare |
POST | /v1/domains/{id}/receiving | Enable receiving or check it again |
POST | /v1/mailboxes | Create an address or catch-all mailbox |
GET | /v1/mailboxes | List mailboxes |
DELETE | /v1/mailboxes/{id} | Delete a mailbox address |
GET | /v1/inbox | List received messages |
GET | /v1/inbox/search | Search received messages |
GET | /v1/inbox/{id} | Read a received message |
DELETE | /v1/inbox/{id} | Move a received message to trash |
GET | /v1/inbox/{id}/attachments/{attachmentId} | Download an attachment |
POST | /v1/inbox/{id}/folder | Move a message to a folder |
POST | /v1/inbox/{id}/star | Set a message's starred state |
POST | /v1/inbox/{id}/read | Set a message's read state |
GET | /v1/requests | List recent API requests |
GET | /v1/suppressions | List suppressed recipients |
POST | /v1/suppressions | Suppress a recipient |
DELETE | /v1/suppressions/{email} | Remove a recipient suppression |
GET | /v1/suppressions/check | Check a recipient's suppression status |
POST | /v1/templates | Create an email template |
GET | /v1/templates | List email templates |
GET | /v1/templates/{slug} | Read an email template |
PATCH | /v1/templates/{slug} | Update an email template |
DELETE | /v1/templates/{slug} | Delete an email template |
POST | /v1/templates/{slug}/preview | Render a template with variables |
GET | /v1/domains/{id}/dns | Read DNS setup and ownership proof |
GET | /v1/domains/ownership | Get proof before registering a domain |
GET | /v1/domains/{id}/dns/records | List managed DNS records |
POST | /v1/domains/{id}/dns/records | Create a DNS record |
PATCH | /v1/domains/{id}/dns/records/{record_id} | Update a DNS record |
DELETE | /v1/domains/{id}/dns/records/{record_id} | Delete a DNS record |
GET | /v1/drafts | List email drafts |
POST | /v1/drafts | Create an email draft |
GET | /v1/drafts/{id} | Read an email draft |
PATCH | /v1/drafts/{id} | Update an email draft |
DELETE | /v1/drafts/{id} | Delete an email draft |
POST | /v1/drafts/{id}/send | Send a draft |
GET | /v1/emails/{id}/content | Read a sent email's stored content |
POST | /v1/inbox/{id}/reply | Reply to a received message |
POST | /v1/inbox/{id}/reply-all | Reply to sender and recipients |
POST | /v1/inbox/{id}/forward | Forward a received message |
POST | /v1/inbox/{id}/restore | Restore a received message to inbox |
GET | /v1/members | List members and their access |
PATCH | /v1/members/{id} | Change a brand member's brands or permissions |
DELETE | /v1/members/{id} | Remove a member |
GET | /v1/invitations | List open invitations |
POST | /v1/invitations | Invite someone to brands |
PATCH | /v1/invitations/{id} | Change an open invitation's brands or permissions |
DELETE | /v1/invitations/{id} | Revoke an open invitation |
POST | /v1/mcp | Call the Model Context Protocol endpoint |
GET | /health | Check process health |