Skip to content

Outbound Email

GET /domains/{name}/outbound

Returns outbound sending configuration, anti-spam settings, and metrics for a domain.

FieldTypeDescription
namestringDomain name
outbound_tierstringshared or dedicated
outbound_statusstringactive or suspended
outbound_daily_limitintegerMax emails/day (0 = unlimited)
outbound_monthly_limitintegerMax emails/month (0 = unlimited)
outbound_sent_todayintegerEmails sent today
outbound_sent_monthintegerEmails sent this month
outbound_enforcementstringsoft (allow + bill) or hard (reject)
bounce_countintegerBounces this period
complaint_countintegerComplaints this period
bounce_ratefloatBounce rate (%)
complaint_ratefloatComplaint rate (%)
ses_verifiedbooleanWhether domain is verified with the mail provider
warmup_profilestringWarm-up speed: fast, standard, or conservative
spike_max_multiplierfloatMax ratio vs 7-day avg before spike protection triggers (0 = disabled)
Terminal window
curl https://mail.emboux.com/domains/example.com/outbound \
-H "Authorization: Bearer {API_KEY}"

PUT /domains/{name}/outbound

Update outbound limits, tier, enforcement, or status for a domain.

All fields are optional — only include the fields you want to change.

FieldTypeDescription
outbound_daily_limitintegerMax emails/day
outbound_monthly_limitintegerMax emails/month
outbound_tierstringshared or dedicated
outbound_enforcementstringsoft or hard
outbound_statusstringactive or suspended
warmup_profilestringfast, standard, or conservative (master only)
spike_max_multiplierfloatSpike detection multiplier (master only, 0 = disabled)
Terminal window
curl -X PUT https://mail.emboux.com/domains/example.com/outbound \
-H "Authorization: Bearer {API_KEY}" \
-H "Content-Type: application/json" \
-d '{"outbound_daily_limit": 500, "outbound_monthly_limit": 10000}'

POST /domains/{name}/outbound/increment

Check quotas and increment the outbound counter by 1. Called by the Policy Daemon for each outgoing email.

Returns allowed: true if the email can be sent. If a soft cap is exceeded, still returns allowed: true with a reason field indicating the exceeded limit.

FieldTypeDescription
namestringDomain name
outbound_sent_todayintegerUpdated daily counter
outbound_sent_monthintegerUpdated monthly counter
allowedbooleanWhether the email is allowed
reasonstring?Reason if blocked or soft-exceeded

Possible reasons:

  • outbound_suspended — domain outbound is suspended (hard cap)
  • outbound_suspended_soft — suspended but allowed (soft cap)
  • daily_limit_exceeded — daily limit hit (hard cap)
  • daily_limit_exceeded_soft — daily limit hit but allowed (soft cap)
  • monthly_limit_exceeded — monthly limit hit (hard cap)
  • monthly_limit_exceeded_soft — monthly limit hit but allowed (soft cap)

POST /domains/{name}/verify

Initiates domain verification with the configured mail provider (Mailgun, SES, etc.). Returns the DNS records you need to configure on your DNS provider.

Available to both master and customer tokens. Customer tokens may only verify domains they own (the API filters by partner_ref; a 404 is returned for any other domain). Master tokens additionally support verifying root/parent domains that are not present in the local domain table — useful when you only registered subdomains.

Outbound email is blocked until the domain is verified.

FieldTypeDescription
namestringDomain name
verification_tokenstringProvider-specific verification value
dkim_tokensstring[]DKIM token identifiers
verifiedbooleanWhether already verified
dns_recordsobject[]DNS records to configure
providerstringProvider used (mailgun, ses)

Each dns_records entry:

FieldTypeDescription
typestringTXT, CNAME, etc.
namestringDNS record name
valuestringDNS record value
Terminal window
curl -X POST https://api.emboux.com/domains/example.com/verify \
-H "Authorization: Bearer {API_KEY}"
{
"name": "example.com",
"verification_token": "v=spf1 include:mailgun.org ~all",
"dkim_tokens": ["krs"],
"verified": true,
"dns_records": [
{"type": "TXT", "name": "example.com", "value": "v=spf1 include:mailgun.org ~all"},
{"type": "TXT", "name": "krs._domainkey.example.com", "value": "k=rsa; p=MIIBIjAN..."},
{"type": "CNAME", "name": "email.example.com", "value": "mailgun.org"}
],
"provider": "mailgun"
}
GET /domains/{name}/verify-status

Checks the current verification status with the configured provider. If verified, automatically updates the domain status.

The {name} can be a parent domain. Verification status is propagated to all subdomains sharing the same verify domain.

FieldTypeDescription
namestringDomain name
verifiedbooleanOverall verification status
verification_statusstringProvider status: Pending, Success, NotStarted, etc.
dkim_statusstringDKIM status: Pending, Success, etc.
providerstringProvider used

POST /domains/{name}/register-subdomain

Registers a subdomain that inherits verification from its parent domain. The behavior varies by provider:

  • Mailgun: registers with dkim_host_authority=true (inherits parent’s DKIM)
  • SES: no-op (DKIM inherited automatically)

Available to master and customer tokens (customers must own the subdomain — see /domains/.../register-subdomain for the canonical reference). The {name} must be a subdomain (3+ domain parts).

Same as Verify response (VerifyResponse schema).


Per-tenant SMTP credentials at the mail provider, wired into Postfix’s sender-dependent SASL map so each tenant’s outbound mail signs with its own provider identity (proper DKIM and Return-Path alignment).

POST /domains/{name}/provider-credential

Master token only. Generates a fresh credential at the provider and installs it for the domain (and every subdomain that inherits it). The plaintext password is returned once — persist it on your side if you need a copy. Re-POST to rotate.

{
"domain": "tenant.com",
"provider": "mailgun",
"login": "[email protected]",
"password": "32-char-hex",
"patterns_installed": ["@tenant.com", "@sub1.tenant.com"],
"sasl_path": "/etc/postfix/sasl_passwd_mailgun"
}
DELETE /domains/{name}/provider-credential

Master token only. Idempotent — calling on a domain with no installed credential returns 200 with patterns_removed: 0.


EmBoux enforces multiple layers of anti-spam protection on every outbound email:

LayerCheckAction
Suppression listRecipient previously bounced or complained (any domain)550 reject — email never reaches the provider
Domain verificationDomain not verified with mail provider550 reject
Domain suspendedOutbound status = suspended (guillotine or manual)452 reject (hard) or warn (soft)
Warm-upNew domain exceeding progressive daily cap452 reject
Spike detectionToday’s volume > 5x the 7-day rolling average452 reject (hard) or warn (soft)
Hourly throttleExceeded ~1/6 of daily limit in one hour452 reject (hard) or warn (soft)
Daily limitExceeded daily sending limit452 reject (hard) or allow + bill (soft)
Monthly limitExceeded monthly sending limit452 reject (hard) or allow + bill (soft)

All checks happen in the Policy Daemon before the email reaches the provider. The suppression list is global — a bounce on one customer’s domain protects all other customers from sending to the same bad address.

New domains start with a base cap of 50 emails/day that grows daily based on the assigned profile:

ProfileGrowthTime to 200/dayTime to 1,000/dayTime to 10,000/day
fast1.8x/day3 days6 days10 days
standard1.1x/day15 days32 days56 days
conservative1.05x/day29 days62 days109 days

The warm-up ends naturally when it reaches the domain’s outbound_daily_limit. All new domains default to standard. Only master tokens can change the profile.

Domains are automatically suspended when:

  • Bounce rate > 0.5% — protects your provider reputation
  • Complaint rate > 0.1% — complaints are treated more severely than bounces

Thresholds are configurable via environment variables (BOUNCE_RATE_THRESHOLD, COMPLAINT_RATE_THRESHOLD).


EmBoux receives bounce and complaint events from each mail provider via provider-specific webhook endpoints. All webhooks feed the same shared logic: update domain counters, add recipients to the global suppression list, and trigger the guillotine if thresholds are exceeded.

POST /webhooks/ses

Receives SNS notifications from Amazon SES. No authentication required (SNS cannot send Bearer tokens).

Handles: SubscriptionConfirmation, Bounce, Complaint.

POST /webhooks/mailgun

Receives Mailgun event webhooks. Validated via HMAC-SHA256 signature (if MAILGUN_WEBHOOK_SIGNING_KEY is configured).

Handles: failed / bounced → Bounce, complained → Complaint.


POST /outbound/reset-daily

Saves today’s send count into a 7-day rolling history (used for spike detection), then resets outbound_sent_today to 0 for all domains. Called by the midnight UTC cron job. Master token required.

FieldTypeDescription
reset_countintegerNumber of domains reset
POST /outbound/reset-monthly

Freezes current monthly counters (for billing), then resets all monthly counters to 0. Master token required.

FieldTypeDescription
frozenobject[]Per-domain frozen values before reset
reset_countintegerNumber of domains reset

Each frozen entry contains: name, partner_ref, outbound_sent_month, outbound_monthly_limit, bounce_count, complaint_count, bounce_rate, complaint_rate.