Outbound Email
Get Outbound Config
Section titled “Get Outbound Config”GET /domains/{name}/outboundReturns outbound sending configuration, anti-spam settings, and metrics for a domain.
Response
Section titled “Response”| Field | Type | Description |
|---|---|---|
name | string | Domain name |
outbound_tier | string | shared or dedicated |
outbound_status | string | active or suspended |
outbound_daily_limit | integer | Max emails/day (0 = unlimited) |
outbound_monthly_limit | integer | Max emails/month (0 = unlimited) |
outbound_sent_today | integer | Emails sent today |
outbound_sent_month | integer | Emails sent this month |
outbound_enforcement | string | soft (allow + bill) or hard (reject) |
bounce_count | integer | Bounces this period |
complaint_count | integer | Complaints this period |
bounce_rate | float | Bounce rate (%) |
complaint_rate | float | Complaint rate (%) |
ses_verified | boolean | Whether domain is verified with the mail provider |
warmup_profile | string | Warm-up speed: fast, standard, or conservative |
spike_max_multiplier | float | Max ratio vs 7-day avg before spike protection triggers (0 = disabled) |
Example
Section titled “Example”curl https://mail.emboux.com/domains/example.com/outbound \ -H "Authorization: Bearer {API_KEY}"Update Outbound Config
Section titled “Update Outbound Config”PUT /domains/{name}/outboundUpdate outbound limits, tier, enforcement, or status for a domain.
Request Body
Section titled “Request Body”All fields are optional — only include the fields you want to change.
| Field | Type | Description |
|---|---|---|
outbound_daily_limit | integer | Max emails/day |
outbound_monthly_limit | integer | Max emails/month |
outbound_tier | string | shared or dedicated |
outbound_enforcement | string | soft or hard |
outbound_status | string | active or suspended |
warmup_profile | string | fast, standard, or conservative (master only) |
spike_max_multiplier | float | Spike detection multiplier (master only, 0 = disabled) |
Example
Section titled “Example”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}'Increment Outbound Counter
Section titled “Increment Outbound Counter”POST /domains/{name}/outbound/incrementCheck 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.
Response
Section titled “Response”| Field | Type | Description |
|---|---|---|
name | string | Domain name |
outbound_sent_today | integer | Updated daily counter |
outbound_sent_month | integer | Updated monthly counter |
allowed | boolean | Whether the email is allowed |
reason | string? | 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)
Domain Verification
Section titled “Domain Verification”Initiate Verification
Section titled “Initiate Verification”POST /domains/{name}/verifyInitiates 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.
Response
Section titled “Response”| Field | Type | Description |
|---|---|---|
name | string | Domain name |
verification_token | string | Provider-specific verification value |
dkim_tokens | string[] | DKIM token identifiers |
verified | boolean | Whether already verified |
dns_records | object[] | DNS records to configure |
provider | string | Provider used (mailgun, ses) |
Each dns_records entry:
| Field | Type | Description |
|---|---|---|
type | string | TXT, CNAME, etc. |
name | string | DNS record name |
value | string | DNS record value |
Example
Section titled “Example”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"}Check Verification Status
Section titled “Check Verification Status”GET /domains/{name}/verify-statusChecks 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.
Response
Section titled “Response”| Field | Type | Description |
|---|---|---|
name | string | Domain name |
verified | boolean | Overall verification status |
verification_status | string | Provider status: Pending, Success, NotStarted, etc. |
dkim_status | string | DKIM status: Pending, Success, etc. |
provider | string | Provider used |
Register Subdomain
Section titled “Register Subdomain”POST /domains/{name}/register-subdomainRegisters 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).
Response
Section titled “Response”Same as Verify response (VerifyResponse schema).
Provider Credentials
Section titled “Provider Credentials”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).
Provision
Section titled “Provision”POST /domains/{name}/provider-credentialMaster 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.
Response 200 OK
Section titled “Response 200 OK”{ "domain": "tenant.com", "provider": "mailgun", "password": "32-char-hex", "patterns_installed": ["@tenant.com", "@sub1.tenant.com"], "sasl_path": "/etc/postfix/sasl_passwd_mailgun"}Revoke
Section titled “Revoke”DELETE /domains/{name}/provider-credentialMaster token only. Idempotent — calling on a domain with no installed credential returns 200 with patterns_removed: 0.
Anti-Spam Protections
Section titled “Anti-Spam Protections”EmBoux enforces multiple layers of anti-spam protection on every outbound email:
| Layer | Check | Action |
|---|---|---|
| Suppression list | Recipient previously bounced or complained (any domain) | 550 reject — email never reaches the provider |
| Domain verification | Domain not verified with mail provider | 550 reject |
| Domain suspended | Outbound status = suspended (guillotine or manual) | 452 reject (hard) or warn (soft) |
| Warm-up | New domain exceeding progressive daily cap | 452 reject |
| Spike detection | Today’s volume > 5x the 7-day rolling average | 452 reject (hard) or warn (soft) |
| Hourly throttle | Exceeded ~1/6 of daily limit in one hour | 452 reject (hard) or warn (soft) |
| Daily limit | Exceeded daily sending limit | 452 reject (hard) or allow + bill (soft) |
| Monthly limit | Exceeded monthly sending limit | 452 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.
Warm-up Profiles
Section titled “Warm-up Profiles”New domains start with a base cap of 50 emails/day that grows daily based on the assigned profile:
| Profile | Growth | Time to 200/day | Time to 1,000/day | Time to 10,000/day |
|---|---|---|---|---|
fast | 1.8x/day | 3 days | 6 days | 10 days |
standard | 1.1x/day | 15 days | 32 days | 56 days |
conservative | 1.05x/day | 29 days | 62 days | 109 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.
Guillotine (Auto-Suspension)
Section titled “Guillotine (Auto-Suspension)”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).
Webhooks
Section titled “Webhooks”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.
SES Webhook
Section titled “SES Webhook”POST /webhooks/sesReceives SNS notifications from Amazon SES. No authentication required (SNS cannot send Bearer tokens).
Handles: SubscriptionConfirmation, Bounce, Complaint.
Mailgun Webhook
Section titled “Mailgun Webhook”POST /webhooks/mailgunReceives Mailgun event webhooks. Validated via HMAC-SHA256 signature (if MAILGUN_WEBHOOK_SIGNING_KEY is configured).
Handles: failed / bounced → Bounce, complained → Complaint.
Reset Counters
Section titled “Reset Counters”Reset Daily
Section titled “Reset Daily”POST /outbound/reset-dailySaves 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.
Response
Section titled “Response”| Field | Type | Description |
|---|---|---|
reset_count | integer | Number of domains reset |
Reset Monthly
Section titled “Reset Monthly”POST /outbound/reset-monthlyFreezes current monthly counters (for billing), then resets all monthly counters to 0. Master token required.
Response
Section titled “Response”| Field | Type | Description |
|---|---|---|
frozen | object[] | Per-domain frozen values before reset |
reset_count | integer | Number of domains reset |
Each frozen entry contains: name, partner_ref, outbound_sent_month, outbound_monthly_limit, bounce_count, complaint_count, bounce_rate, complaint_rate.