SMTP Pools
Configure custom SMTP relay servers and route outbound email through your own infrastructure
SMTP pools let you route outbound email through your own SMTP relay instead of MisarMail's shared sending infrastructure. This is useful when you have an existing arrangement with a provider like Amazon SES, Postfix, Mailgun, or SendGrid, or when you need isolated sending pools for different business units.
The same functionality is available in the dashboard at Settings → SMTP Pools.
Requires an active MisarMail session (dashboard only). Passwords and DKIM private keys are never returned — responses expose only hasPassword and hasDkim.
List SMTP pools
/api/smtp-poolsReturns all configured SMTP pools for the account.
Response fields
poolsArray<object>Each pool includes id, name, pool_type (transactional | marketing | cold), host, port, username, use_tls, max_connections, max_messages, dkim_selector, dkim_domain, is_active, is_system, health_status, created_at, plus the booleans hasPassword and hasDkim. The encrypted password and DKIM private key are stripped from the response.
{
"pools": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Amazon SES — us-east-1",
"pool_type": "transactional",
"host": "email-smtp.us-east-1.amazonaws.com",
"port": 587,
"username": "AKIAIOSFODNN7EXAMPLE",
"use_tls": true,
"max_connections": 5,
"max_messages": 100,
"dkim_selector": "misarmail",
"dkim_domain": null,
"is_active": true,
"is_system": false,
"health_status": "unknown",
"created_at": "2026-05-01T00:00:00Z",
"hasPassword": true,
"hasDkim": false
}
]
}Create SMTP pool
/api/smtp-poolsCreate a new SMTP pool.
Request body
namestringbodyrequiredDisplay name for the pool.
poolTypetransactional | marketing | coldbodyrequiredWhich sending category this pool serves.
hoststringbodyrequiredSMTP server hostname. Wildcard domains are rejected.
portintegerbodydefault: 587SMTP port (1–65535).
usernamestringbodyrequiredSMTP authentication username.
passwordstringbodyrequiredSMTP authentication password (stored encrypted).
useTlsbooleanbodydefault: trueWhether to connect over TLS/STARTTLS.
maxConnectionsintegerbodydefault: 5Maximum concurrent SMTP connections (1–50).
maxMessagesintegerbodydefault: 100Maximum messages per connection (1–1000).
generateDkimbooleanbodydefault: falseGenerate a DKIM key pair for this pool. When true, the response includes a dkimDnsRecord to publish.
dkimDomainstringbodyDomain the DKIM key signs for (used with generateDkim).
dkimSelectorstringbodydefault: misarmailDKIM selector (max 63 chars).
Response fields
poolobjectThe created pool (password and DKIM private key stripped).
dkimDnsRecordobject | nullThe DKIM TXT record to publish when generateDkim was true; otherwise null.
createdbooleanAlways true on success.
curl -X POST /api/smtp-pools \
-H "Content-Type: application/json" \
-d '{
"name": "Amazon SES — us-east-1",
"poolType": "transactional",
"host": "email-smtp.us-east-1.amazonaws.com",
"port": 587,
"username": "AKIAIOSFODNN7EXAMPLE",
"password": "your-ses-smtp-password",
"useTls": true
}'{
"pool": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Amazon SES — us-east-1",
"pool_type": "transactional",
"host": "email-smtp.us-east-1.amazonaws.com",
"port": 587,
"use_tls": true,
"is_active": true,
"hasPassword": true,
"hasDkim": false
},
"dkimDnsRecord": null,
"created": true
}const res = await fetch('/api/smtp-pools', {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name: 'Amazon SES — us-east-1',
poolType: 'transactional',
host: 'email-smtp.us-east-1.amazonaws.com',
port: 587,
username: process.env.SES_USERNAME,
password: process.env.SES_PASSWORD,
useTls: true,
}),
});
const { pool, dkimDnsRecord } = await res.json();Common provider settings
| Provider | Host | Port | useTls |
|---|---|---|---|
| Amazon SES | email-smtp.<region>.amazonaws.com | 587 | true |
| Mailgun | smtp.mailgun.org | 587 | true |
| SendGrid | smtp.sendgrid.net | 587 | true |
| Postfix (self-hosted) | Your server IP/hostname | 587 | true |
| Gmail SMTP | smtp.gmail.com | 465 | true |
Update SMTP pool
/api/smtp-poolsUpdate a pool you own. Pass the pool id in the body along with any fields to change. System pools cannot be modified.
Request body
idUUIDbodyrequiredID of the pool to update.
isActivebooleanbodyEnable or disable the pool.
Any field accepted by POST (name, poolType, host, port, username, password, useTls, maxConnections, maxMessages, generateDkim, dkimDomain, dkimSelector) may also be sent to update it. Omitted fields are left unchanged.
Response fields
poolobjectThe updated pool.
dkimDnsRecordobject | nullPresent when DKIM was (re)generated during the update.
updatedbooleanAlways true on success.
curl -X PUT /api/smtp-pools \
-H "Content-Type: application/json" \
-d '{ "id": "550e8400-e29b-41d4-a716-446655440000", "isActive": false }'{
"pool": { "id": "550e8400-e29b-41d4-a716-446655440000", "is_active": false },
"dkimDnsRecord": null,
"updated": true
}Delete SMTP pool
/api/smtp-poolsDelete a pool you own. The pool id is passed as a query parameter. A pool that is still referenced by one or more aliases cannot be deleted — reassign those aliases first. System pools cannot be deleted.
Query parameters
idUUIDqueryrequiredID of the pool to delete.
Response fields
deletedbooleantrue when the pool was removed.
curl -X DELETE "/api/smtp-pools?id=550e8400-e29b-41d4-a716-446655440000"{ "deleted": true }{ "error": "Cannot delete a pool that is still assigned to aliases" }Test SMTP connection
/api/smtp-pools/:id/testRuns a live connectivity check against the pool's SMTP server: TCP connect → EHLO → STARTTLS (on port 587) → success. It does not send an email. The response is returned at HTTP 200 even when the check fails — inspect the status field.
Path parameters
idUUIDpathrequiredID of the SMTP pool to test.
Response fields
successbooleantrue when the connection check passed.
statusstringhealthy when the check passed, unhealthy otherwise. Persisted to the pool's health_status.
errorstringThe underlying SMTP/connection error, present only when status is unhealthy.
{ "success": true, "status": "healthy" }{
"success": false,
"status": "unhealthy",
"error": "Connection error: connect ECONNREFUSED 198.51.100.1:587"
}Status codes
- 200 — OK. List, update, delete, or test completed (a failed connectivity test still returns
200withstatus: "unhealthy"). - 201 — Created. Pool created.
- 400 — Bad request. Failed body validation, missing/invalid pool
id, or invalid JSON. - 401 — Unauthorized. No active session.
- 403 — Forbidden. The pool is a system pool, or it does not belong to you.
- 404 — Not found. Pool not found.
- 409 — Conflict. The pool is still assigned to one or more aliases.
- 500 — Server error. Failed to create, update, or delete the pool.
Using an SMTP pool for sends
A send never references a pool directly — it references an alias, and the alias routes through its assigned SMTP pool. Assign a pool to an alias (see Email Aliases), then reference that alias by id in your send request:
curl -X POST https://api.misar.io/mail/v1/send \
-H "Authorization: Bearer msk_..." \
-H "Content-Type: application/json" \
-d '{
"to": [{ "email": "user@example.com" }],
"from": { "email": "hello@example.com", "name": "Acme" },
"subject": "Your order is confirmed",
"html": "<p>Thanks for your order!</p>",
"alias_id": "660e8400-e29b-41d4-a716-446655440111"
}'If alias_id is omitted, MisarMail uses your default alias (and its pool).
Amazon SES setup notes
- Verify your sending domain in the SES console
- Request production access if you are out of the SES sandbox
- Create SMTP credentials in SES → Account dashboard → SMTP settings → Create SMTP credentials
- Use port
587with STARTTLS (useTls: true) - Ensure your EC2 or VPS security group allows outbound TCP on port 587
Amazon SES SMTP credentials (access key + secret) are different from your AWS IAM credentials. Generate them specifically in the SES console.