Transactional email for students

The free tier is 3,000 emails a month and 100 a day with no card, which covers a class project, a hackathon, and the demo afterwards. This page also explains the three DNS records everyone copies without understanding, because knowing what they do is more useful than a working project you cannot explain.

01

Take a key and send from onboarding@emails.sh.

No domain, no DNS, no card. Your first send works within a minute of signing up.

02

Install the client for your language.

`npm install @emails.sh/sdk` for node, `pip install emailssh` for python. Both are one call over HTTPS.

03

Keep the key in an environment variable.

EMAILSSH_API_KEY, never a literal in a file you push to GitHub. Public repositories get scraped for keys within minutes.

04

Add a domain when you have one.

If you own a domain, add it and paste two DNS records to send from your own address. Until then the sandbox address is enough.

Your first send

send.py, runnable as soon as EMAILSSH_API_KEY is set.

Your first send
import os

from emailssh import Emailssh

# os.environ raises immediately if the variable is missing, which is a better
# failure than a None key producing a confusing 401 later on.
emails = Emailssh(os.environ["EMAILSSH_API_KEY"])

result = emails.send(
    # Works before you own a domain. Swap it once you verify your own.
    from_="Project <onboarding@emails.sh>",
    to=["you@example.com"],
    subject="Your confirmation code",
    html="<p>Your confirmation code is <strong>418290</strong>.</p>",
    text="Your confirmation code is 418290.",
)

# {"id": "...", "status": "queued"}. Queued means accepted, not yet delivered.
print(result["id"], result["status"])

Worth knowing

01

SPF says which servers may send for your domain

It is a TXT record listing authorised senders. A receiving server checks the sending server against that list. If your domain has no SPF record, your mail is judged on nothing.

02

DKIM is a signature that proves the message was not altered

Your DNS publishes a public key, the sending service signs each message with the private half, and the receiver verifies it. This is why a forwarded copy can still be shown as authentic.

03

DMARC tells receivers what to do when SPF and DKIM fail

p=none means report only, quarantine means spam folder, reject means refuse. Start at none, read the reports for a fortnight, then tighten. It also asks for aggregate reports, which is how you find out who is spoofing you.

04

Gmail SMTP is fine for a script and wrong for a deployed project

It needs an app password, caps you at roughly 500 messages a day, and most hosting platforms block outbound port 587, so the project that worked in your terminal sends nothing after deployment.

What arrives

One call to POST /v1/emails, and this is the message. The delivery result for it is on GET /v1/emails/:id a second later.

Sent
To:      you@example.com
Subject: Your confirmation code

Your confirmation code is 418290.

Questions

Is it really free?

3,000 emails a month and 100 a day, no credit card. You are not asked for payment details to start.

Do I need to own a domain?

No. onboarding@emails.sh sends from the first minute. A domain only matters when you want mail to come from your own address.

I pushed my API key to GitHub. What now?

Revoke it at https://emails.sh/dashboard and create a new one. Removing the commit is not enough, because the key was public the moment it was pushed.

Why is my email in the spam folder?

Usually an unverified domain, or an HTML-only message with a single link. Verify the domain, send both html and text, and write a subject line that is not all capitals.

Can I use this for a hackathon demo?

Yes. The daily limit of 100 is the one to watch if you demo a signup flow repeatedly, so test with a small number of addresses.