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.

MethodPathAction
POST/v1/emailsSend an email
GET/v1/emailsList sent emails
GET/v1/emails/{id}Read delivery status and events
POST/v1/brandsCreate a sending brand
GET/v1/brandsList brands
GET/v1/brands/{id}Read a sending brand
PATCH/v1/brands/{id}Change a brand's name or slug
POST/v1/brands/{id}/provisionActivate a local brand
POST/v1/domainsAdd and provision a sending domain
GET/v1/domainsList 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}/provisionRetry domain provisioning
POST/v1/domains/{id}/checkRefresh domain verification
POST/v1/domains/{id}/publish-dnsPublish DNS records to Cloudflare
POST/v1/domains/{id}/receivingEnable receiving or check it again
POST/v1/mailboxesCreate an address or catch-all mailbox
GET/v1/mailboxesList mailboxes
DELETE/v1/mailboxes/{id}Delete a mailbox address
GET/v1/inboxList received messages
GET/v1/inbox/searchSearch 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}/folderMove a message to a folder
POST/v1/inbox/{id}/starSet a message's starred state
POST/v1/inbox/{id}/readSet a message's read state
GET/v1/requestsList recent API requests
GET/v1/suppressionsList suppressed recipients
POST/v1/suppressionsSuppress a recipient
DELETE/v1/suppressions/{email}Remove a recipient suppression
GET/v1/suppressions/checkCheck a recipient's suppression status
POST/v1/templatesCreate an email template
GET/v1/templatesList 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}/previewRender a template with variables
GET/v1/domains/{id}/dnsRead DNS setup and ownership proof
GET/v1/domains/ownershipGet proof before registering a domain
GET/v1/domains/{id}/dns/recordsList managed DNS records
POST/v1/domains/{id}/dns/recordsCreate 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/draftsList email drafts
POST/v1/draftsCreate 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}/sendSend a draft
GET/v1/emails/{id}/contentRead a sent email's stored content
POST/v1/inbox/{id}/replyReply to a received message
POST/v1/inbox/{id}/reply-allReply to sender and recipients
POST/v1/inbox/{id}/forwardForward a received message
POST/v1/inbox/{id}/restoreRestore a received message to inbox
GET/v1/membersList 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/invitationsList open invitations
POST/v1/invitationsInvite 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/mcpCall the Model Context Protocol endpoint
GET/healthCheck process health