Bring Your Own SES
BYOC routes email through your own AWS SES account via a short-lived IAM role. Your email content never touches our database. Your sender reputation is isolated from every other SendFleet customer.
How it works
SendFleet operates two isolated AWS accounts. The BYOC relay uses AWS STS to assume your IAM role for a 15-minute session and dispatches your email directly through your SES. Neither your email content nor your recipient addresses ever reach our database.
Security - ExternalId & confused deputy
Every BYOC configuration has a unique, randomly generated ExternalId (48 hex characters = 192 bits of entropy). It must appear in your IAM trust policy's Condition block.
Without ExternalId, any party who learns your Role ARN could ask our infrastructure to assume it on their behalf - this is the confused deputy attack. With ExternalId, only requests carrying the correct value (only we know it) can assume your role.
Step 1 - Create the IAM Role
In your AWS Console, go to IAM → Roles → Create role. Select Custom trust policy and paste the policy below. The role name must be exactly SendFleet-BYOC-Role - our relay infrastructure is only permitted to assume roles with this exact name.
Trust policy
Copy your ExternalId from Dashboard → Settings → BYOC sectionfirst (it's generated when you first save your config).
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::979054355634:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "<YOUR_EXTERNAL_ID_FROM_SETTINGS>"
}
}
}
]
}Required IAM permissions
Attach a permissions policy to the role with the following actions. Create a new inline policy or attach a custom managed policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "SendFleetSESPermissions",
"Effect": "Allow",
"Action": [
"ses:SendEmail",
"ses:SendRawEmail",
"ses:VerifyDomainIdentity",
"ses:VerifyDomainDkim",
"ses:GetIdentityVerificationAttributes",
"ses:GetIdentityDkimAttributes",
"ses:GetIdentityMailFromDomainAttributes",
"ses:SetIdentityMailFromDomain",
"ses:DeleteIdentity",
"ses:GetAccountSendingEnabled",
"ses:GetSendQuota"
],
"Resource": "*"
}
]
}| Permission | Used for |
|---|---|
| ses:SendEmail, ses:SendRawEmail | Delivering email on your behalf |
| ses:VerifyDomainIdentity, ses:VerifyDomainDkim | Registering sending domains via the dashboard |
| ses:GetIdentityVerificationAttributes, ses:GetIdentityDkimAttributes | Checking domain verification status |
| ses:GetIdentityMailFromDomainAttributes, ses:SetIdentityMailFromDomain | Configuring MAIL FROM subdomain |
| ses:DeleteIdentity | Removing domains when you delete them |
| ses:GetAccountSendingEnabled, ses:GetSendQuota | Sandbox detection during validation |
Step 2 - Connect in SendFleet
Go to Dashboard → Settings → BYOC section. Enter your Role ARN and select your SES region. Click Validate & save.
We validate by:
- → Calling
sts:AssumeRolewith your ExternalId - confirms the trust policy is correct - → Calling
ses:GetAccountSendingEnabled- confirms sending is enabled - → Calling
ses:GetSendQuota- confirms you're out of sandbox mode (production quota must exceed 200 emails/day)
Step 3 - Add a sending domain
Once the role is validated, go to Dashboard → Domains → Add BYOC domain. Enter your root domain (e.g. acme.com - not a subdomain).
We will:
- → Call
ses:VerifyDomainIdentityin your account - gives you a TXT token to add to DNS - → Call
ses:VerifyDomainDkimin your account - gives you 3 CNAME tokens to add to DNS - → Configure a MAIL FROM subdomain (
send.yourdomain.com) for bounce routing
Add all DNS records shown. Then use the per-record Verify buttons in the domain detail page. DNS propagation can take up to 48 hours. See the full DNS Records guide →
Step 4 - Send
Once domain ownership and DKIM are both verified, you're ready to send. Use the domain's address in from_email:
curl -X POST https://sendfleet.net/api/send/ \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "customer@example.com",
"from_email": "hello@acme.com",
"from_name": "Acme",
"subject": "Welcome!",
"message": "Thanks for joining Acme."
}'
# Response will include "mode": "byoc"Privacy guarantee
| Data | Stored by SendFleet? |
|---|---|
| Recipient email address | Never |
| Email subject | Never |
| Email body (text or HTML) | Never |
| Monthly send count | Yes (one number, Starter plan only) |
| IAM Role ARN | Yes (required for routing) |
| ExternalId | Yes (required for STS) |
Troubleshooting
| Error | Fix |
|---|---|
| Could not assume role | Check the trust policy's Principal.AWS matches Account's ID exactly and the sts:ExternalId condition matches your ExternalId from settings. |
| Sending is disabled on your SES account | Go to AWS Console → SES → Account dashboard and enable sending. |
| SES account is in sandbox mode | Your 24-hour send quota is ≤ 200. Request production access → |
| Missing ses:GetSendQuota permission | Ensure your permissions policy includes all 11 actions listed in Step 1. |
| IAM change not taking effect | Wait 15 seconds for global IAM propagation and try validation again. |
| byoc_not_configured (503) | SendFleet Account credentials are misconfigured on our end. Contact support. |