curl
The API from a shell, which is also the version to paste into a bug report.
Nothing here needs a client library. If you can make an HTTPS request, you can send email, and curl is the shortest way to prove a key works before you write any code.
Send
curl -X POST https://emails.sh/v1/emails \
-H "Authorization: Bearer $EMAILSSH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "Acme <hello@acme.com>",
"to": ["ada@example.com"],
"subject": "Your receipt from Acme",
"html": "<p>Thanks for your order. Your receipt is attached.</p>",
"text": "Thanks for your order. Your receipt is attached."
}'{
"id": "em_01J9X8Q2K7Y4RN3M",
"status": "queued"
}The key comes from https://emails.sh/dashboard/api-keys and lives in the environment, not in the command: a key typed inline ends up in your shell history and in the terminal scrollback you paste into an issue.
Read the result
# Send and keep the id
ID=$(curl -s -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":"Test","text":"Hello."}' \
| jq -r .id)
# Ask what happened to it
curl -s https://emails.sh/v1/emails/$ID \
-H "Authorization: Bearer $EMAILSSH_API_KEY" | jq .statusFrom a file
A body with real HTML in it is easier to keep in a file than to quote in a shell. -d @file reads it, and the file can be generated by anything.
cat > email.json <<'JSON'
{
"from": "Acme <hello@acme.com>",
"to": ["ada@example.com"],
"subject": "Your receipt from Acme",
"html": "<p>Thanks for your order.</p>",
"text": "Thanks for your order."
}
JSON
curl -X POST https://emails.sh/v1/emails \
-H "Authorization: Bearer $EMAILSSH_API_KEY" \
-H "Content-Type: application/json" \
-d @email.jsonAttach a file
PDF=$(base64 -w 0 receipt.pdf) # macOS: base64 -i receipt.pdf
curl -X POST https://emails.sh/v1/emails \
-H "Authorization: Bearer $EMAILSSH_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg pdf "$PDF" '{
from: "Acme <hello@acme.com>",
to: ["ada@example.com"],
subject: "Your receipt",
html: "<p>Your receipt is attached.</p>",
attachments: [{ filename: "receipt.pdf", content_type: "application/pdf", content_base64: $pdf }]
}')"Fail loudly in a script
curl exits 0 on a 422 by default, which is how a broken deploy script stays quiet for a week. --fail-with-body gives you a non-zero exit and still prints the reason.
set -euo pipefail
curl --fail-with-body -sS -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":"Deploy","text":"Shipped."}'