# Transactional email for students

3,000 emails a month free with no credit card, plus what SPF, DKIM, and DMARC actually do and why Gmail SMTP breaks once you deploy.

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.

## What happens next

1. **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.
1. **Install the client for your language.** `npm install @emails.sh/sdk` for node, `pip install emailssh` for python. Both are one call over HTTPS.
1. **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.
1. **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.

```py
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

### 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.

### 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.

### 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.

### 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.


## 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.


## One send

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

Your confirmation code is 418290.
```

Docs: https://emails.sh/docs.md