Quickstart
A key, a first email, and a verified sending domain.
Three steps. The first two take about a minute and prove the integration works. The third is DNS, and it is the only part you cannot finish in this tab.
1. Get a key
Sign up at https://emails.sh/signup, open https://emails.sh/dashboard/api-keys, and create a key. It starts with esh_ and is shown once. Put it in your environment rather than in a source file.
# .env, and check that .env is in .gitignore.
# The key comes from https://emails.sh/dashboard/api-keys.
EMAILSSH_API_KEY=esh_your_key_here
# or, for a one-off in a shell
export EMAILSSH_API_KEY="esh_your_key_here"2. Send an email
Before any DNS exists you can send from onboarding@emails.sh, to an address you own. The sandbox address only sends to addresses that belong to the workspace, which is what keeps it from being an open relay.
curl -X POST https://emails.sh/v1/emails \
-H "Authorization: Bearer $EMAILSSH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "onboarding@emails.sh",
"to": ["you@example.com"],
"subject": "First email from emails.sh",
"html": "<p>It works.</p>"
}'{
"id": "em_01J9X8Q2K7Y4RN3M",
"status": "queued"
}Keep the id. GET /v1/emails/em_01J9X8Q2K7Y4RN3M tells you whether the receiving server took it, and if it bounced, what the remote server said.
3. Send from your own domain
Add a subdomain you control rather than the domain your own mail runs on: mail.acme.com, not acme.com. A subdomain keeps a sending reputation apart from your human email and lets you publish an MX record without competing with your existing inbox.
curl -X POST https://emails.sh/v1/domains \
-H "Authorization: Bearer $EMAILSSH_API_KEY" \
-H "Content-Type: application/json" \
-d '{"domain": "mail.acme.com"}'{
"id": "dom_01J9X8W1A2",
"domain": "mail.acme.com",
"verification_status": "pending",
"records": [
{ "type": "CNAME", "name": "abc123._domainkey.mail.acme.com", "value": "abc123.dkim.amazonses.com", "purpose": "DKIM" },
{ "type": "CNAME", "name": "def456._domainkey.mail.acme.com", "value": "def456.dkim.amazonses.com", "purpose": "DKIM" },
{ "type": "CNAME", "name": "ghi789._domainkey.mail.acme.com", "value": "ghi789.dkim.amazonses.com", "purpose": "DKIM" },
{ "type": "TXT", "name": "_emailssh.mail.acme.com", "value": "emailssh-verify=9f2c4e1b", "purpose": "ownership" },
{ "type": "TXT", "name": "mail.acme.com", "value": "v=spf1 include:amazonses.com ~all", "purpose": "SPF" },
{ "type": "TXT", "name": "_dmarc.mail.acme.com", "value": "v=DMARC1; p=none;", "purpose": "DMARC" }
]
}Publish those records at your DNS host, then call POST /v1/domains/dom_01J9X8W1A2/verify. It reads DNS and answers with found: true or false per record, so a missing one is named rather than guessed at. Most hosts propagate in under fifteen minutes.
Once verification passes, change from to an address on that domain and send again. Nothing else in your code changes.