to anna@northwind.com
Hi Anna, the refund for order 4012 went out this morning. It should land in 3 to 5 working days.
Password resets, receipts and alerts, from your own domain, landing in the inbox.
Paste this at your coding assistant
Add emails.sh to this project. Read https://emails.sh/llms.txt 3,000 emails a month, free, no credit card.
Emails
Every message this workspace has sent, and what happened to it.
Recent sends
Delivery events
accepted by mx1.lumen.co in 840ms
Helsinki, FI
550 5.1.1 no such mailbox, address suppressed
https://acme.com/reset
accepted by aspmx.l.google.com in 612ms
Berlin, DE
accepted by mx.northwind.com in 371ms
Every sample is a complete file. Copy it, add your key, and it runs.
// npm install @emails.sh/sdk
// Your key is on https://emails.sh/dashboard/keys and starts with esh_
import { Emailssh } from '@emails.sh/sdk';
const mail = new Emailssh({ apiKey: process.env.EMAILSSH_API_KEY });
async function sendLoginCode(to, code) {
const sent = await mail.send({
from: 'Acme <hello@acme.com>',
to,
subject: 'Your login code',
html: `<p>Your code is <strong>${code}</strong>.</p>`,
text: `Your code is ${code}.`
});
return sent.id;
}
try {
const id = await sendLoginCode('someone@example.com', '123456');
console.log('queued as', id);
} catch (error) {
// Refusals come back as prose that says what to do next, so this is
// worth logging verbatim rather than reducing to a status code.
console.error(error.message);
}We answer their APIs exactly as they do, so you keep the package you already installed.
# .env -RESEND_BASE_URL=https://api.resend.com -RESEND_API_KEY=re_your_old_key +RESEND_BASE_URL=https://emails.sh/resend +RESEND_API_KEY=esh_your_new_key # Nothing else changes. Same package, same import, same call, # same id field on the way back. Deleting these two rolls it back.
Every failure comes back with the fix written out, not just a code to look up.
Every error, and what to do about itHTTP/1.1 422 Unprocessable Entity
content-type: application/json
{
"error": "invalid_from_domain",
"message": "The domain acme.com is not verified on this workspace. Verify it at https://emails.sh/dashboard/domains, or send from onboarding@emails.sh while you are testing."
}On every plan, including the free one. Nothing here is an add-on.
Send an idempotency_key and the repeat comes back with the id of the original.
Set send_at and the message leaves then. Cancel any time before it does.
A hard bounce or a complaint suppresses the address, and the next send to it is refused.
A signed POST on every event, retried with backoff, and replayable when your endpoint was down.
One round trip instead of a hundred, and an id back for each.
Nothing reaches the internet, but you still get a real id, real events, and real webhooks.
Copy five DNS records, then check them from the same page. Your mail is signed as you from then on.
Domains, pricing, and the mail that comes back.
emails.sh is a transactional email API for developers. Your app sends verification links, password resets, receipts, and alerts with one POST to https://emails.sh/v1/emails, from a domain you have verified, and every message gets an id whose delivery history you can look up later.
The API is the same shape, so a migration is a base URL and a key. Two things differ. Receiving is included: mail sent back to your domain is parsed, threaded, and posted to a webhook rather than discarded. And every integration path is built for a coding assistant to walk, from llms.txt to markdown docs to an installable skill.
Paste this at the assistant: "Add emails.sh to this project. Read https://emails.sh/llms.txt" The assistant fetches the machine-readable docs, writes the call in your framework, installs the SDK, and tells you which DNS records to add.
A POST to https://emails.sh/v1/emails with an Authorization: Bearer esh_... header and a JSON body of from, to, subject, and html. The response is an id and a status of queued. That one endpoint is enough to run a product on for years.
Node and TypeScript, Python, PHP, Ruby, Go, Rust, Java, C# and .NET, and Elixir, plus curl for anything else. Framework guides sit on top of those for Next.js, Nuxt, SvelteKit, Remix, Astro, Laravel, Rails, Django, FastAPI, Spring, Phoenix, Express, Hono, and Cloudflare Workers.
A test send from onboarding@emails.sh works the moment you have a key, which is about two minutes from signing up. Sending from your own domain takes as long as your DNS provider needs to publish the records, usually minutes.
3,000 emails a month, free. No credit card.