Send Your First Email
First email in under 3 minutes with a test key — no DNS required
Send your first email in under three minutes. You don't need to configure DNS to get started: a test API key runs the entire pipeline — statuses, timeline, webhooks — without delivering real email. Going live is the last step, not the first.
Step 1: Get a test API key
The onboarding wizard offers one right after signup. You can also create one anytime in the dashboard under Settings → API keys (pick the Test environment), or via API if you already have a key:
curl -X POST https://api.tratto.email/v1/api-keys \
-H "Authorization: Bearer YOUR_EXISTING_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"quickstart","env":"test","permissions":["emails:send","emails:read"]}'Test keys start with tratto_test_, live keys with tratto_live_.
The key is shown only once. Treat it like a password, never expose it client-side.
Step 2: Send an email
Any syntactically valid from address works in test mode — no verified
domain needed.
cURL
curl -X POST https://api.tratto.email/v1/emails \
-H "Authorization: Bearer tratto_test_..." \
-H "Content-Type: application/json" \
-d '{
"from": "[email protected]",
"to": "[email protected]",
"subject": "Hello from Tratto!",
"text": "If you see this, it works!"
}'Node.js
const response = await fetch('https://api.tratto.email/v1/emails', {
method: 'POST',
headers: {
'Authorization': 'Bearer tratto_test_...',
'Content-Type': 'application/json',
},
body: JSON.stringify({
from: '[email protected]',
to: '[email protected]',
subject: 'Hello from Tratto!',
text: 'If you see this, it works!',
}),
});
const { data } = await response.json();
console.log('Email ID:', data.id); // email_...
console.log('Live mode:', data.livemode); // falsePython
import requests
response = requests.post(
'https://api.tratto.email/v1/emails',
headers={
'Authorization': 'Bearer tratto_test_...',
'Content-Type': 'application/json',
},
json={
'from': '[email protected]',
'to': '[email protected]',
'subject': 'Hello from Tratto!',
'text': 'If you see this, it works!',
},
)
data = response.json()['data']
print(data['id'], data['livemode']) # email_... FalseResponse:
{
"data": {
"id": "email_xyz789",
"livemode": false
}
}Step 3: Watch it move through the pipeline
Within a few seconds the email goes queued → sent → delivered, with events
in its timeline — exactly like production traffic:
curl https://api.tratto.email/v1/emails/email_xyz789 \
-H "Authorization: Bearer tratto_test_..."Special recipient addresses simulate the other outcomes:
| Recipient | Outcome |
|---|---|
[email protected] (or any other address) | delivered |
[email protected] | permanent bounce — email ends failed |
[email protected] | transient bounce |
[email protected] | spam complaint |
If you have a webhook registered, these events are
delivered to it too, with livemode: false in the payload. See
Test mode for the full semantics.
Go live: verify your domain
Real email comes from a domain you own. Add it:
curl -X POST https://api.tratto.email/v1/domains \
-H "Authorization: Bearer tratto_live_..." \
-H "Content-Type: application/json" \
-d '{"domain":"yourdomain.com"}'Response (values are examples — always use the ones from your response):
{
"data": {
"id": "dom_abc123",
"domain": "yourdomain.com",
"status": "pending",
"records": [
{ "type": "CNAME", "host": "token1._domainkey.yourdomain.com", "value": "token1.dkim.amazonses.com", "purpose": "dkim" },
{ "type": "CNAME", "host": "token2._domainkey.yourdomain.com", "value": "token2.dkim.amazonses.com", "purpose": "dkim" },
{ "type": "CNAME", "host": "token3._domainkey.yourdomain.com", "value": "token3.dkim.amazonses.com", "purpose": "dkim" },
{ "type": "TXT", "host": "yourdomain.com", "value": "v=spf1 include:amazonses.com ~all", "purpose": "spf" },
{ "type": "TXT", "host": "_dmarc.yourdomain.com", "value": "v=DMARC1; p=quarantine; rua=mailto:[email protected]", "purpose": "dmarc" }
]
}
}Add every record from the response at your DNS provider. The three DKIM CNAME records are required for verification; SPF and DMARC are strongly recommended for deliverability.
If your domain already has an SPF record (from Cloudflare Email Routing, Google
Workspace, Microsoft 365 and similar), add include:amazonses.com to it
instead of creating a second one, for example
v=spf1 include:amazonses.com include:_spf.mx.cloudflare.net ~all. A domain
must have exactly one v=spf1 record: two break SPF for every sender.
Amazon SES notes that DNS changes can take up to 72 hours to propagate. Verification also runs automatically: Tratto re-checks pending domains every 10 minutes.
Verify when ready:
curl -X POST https://api.tratto.email/v1/domains/dom_abc123/verify \
-H "Authorization: Bearer tratto_live_..."Once status is verified, swap your test key for a live one
(tratto_live_...) — same code, real delivery. That's the only change.
Next Steps
- Everything about test keys? See Test mode
- Send with templates? See Templates
- Track opens and clicks? Set up Webhooks
- Understand all fields? Read Send Email
- Use an SDK? Try Node.js SDK or Python SDK
Stuck? Check Error Codes or Authentication.
Edit this page on GitHub
Last updated on