Send your first email

A full walkthrough, including what to do when it does not work.

This is the long version of Quick Start, with the failure modes spelled out. Follow it once end to end and you will have a sending setup that is actually correct rather than one that happened to work.

Step 1 — Create an account

Sign up at rovela.dev/signup. You start on the free plan, which sends real mail: there is no separate test mode, and no key that behaves differently from a production one.

Step 2 — Add a sending domain

Open Domains and add the domain you want mail to come from. It has to be a domain you control, because the next step asks you to prove it by publishing DNS records — and because a sender you cannot prove you own is a sender anyone could impersonate.

Use a subdomain if you are not ready to commit the root domain. mail.example.com is common and keeps your reputation for transactional mail separate from everything else the root domain does.

Step 3 — Publish the DNS records

The dashboard shows four records. They are not interchangeable, and adding three of them is not a partial success:

  • SPF (TXT) lists the servers allowed to send for the domain.
  • DKIM (TXT) carries a public key that lets a receiver check your mail was not altered.
  • DMARC (TXT at _dmarc.) tells receivers what to do when the first two fail.
  • Return-path (MX, and a matching TXT) routes bounces back to us.

Copy the values from the dashboard rather than from anywhere else — the DKIM key is generated for your domain specifically.

Then wait

DNS changes are not instant. How long depends on the TTL your provider used, and typically means minutes rather than seconds. Click Verify; if it fails, wait a few minutes and try again before you change anything. Editing records that were already correct is the most common way people turn a five-minute wait into an hour of debugging.

Step 4 — Create an API key

Open API Keys. Choose sending_access unless you specifically need to manage domains or templates over the API. Copy the key now — it is shown once and cannot be retrieved later.

Step 5 — Send

curl -X POST https://api.rovela.dev/emails \
  -H "Authorization: Bearer re_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Acme <hello@yourdomain.com>",
    "to": "you@example.com",
    "subject": "Hello from Rovela",
    "html": "<p>It worked.</p>"
  }'

Success looks like this, with a fresh id each time:

{"object": "email", "id": "9f1c2e40-..."}

Step 6 — Confirm delivery

The 200 means the message is queued, not that it arrived. Give it a moment, then read the events for that message:

curl https://api.rovela.dev/emails/9f1c2e40-.../events \
  -H "Authorization: Bearer re_your_api_key"

You are looking for email.sent followed by email.delivered. If you see email.bounced instead, the message was accepted and then rejected by the receiving server — check the address you sent to before assuming anything is wrong with your setup.

When it does not work

"Domain not found" or a 400 naming your domain

The from address is on a domain that is not in your organization, or is still unverified. Two different causes, one message — check the domain list first, then its verification status.

401 Invalid token

Either the key is wrong or revoked, or you are calling a dashboard endpoint that wants a session token. A perfectly valid API key gets a 401 from GET /domains.

429 Too Many Requests

The rate limit is per key. If you are sending a batch, each message counts individually, so a large batch can trip this partway through — see the retry guidance in Send Email.

It sent, but it landed in spam

This is almost always DNS rather than the API. Check, in order: that the DKIM record is actually published at the selector the dashboard gave you, that you have exactly one SPF record (two is a permanent fail), and that your DMARC policy is not p=reject on a domain with no sending history. A brand-new domain also has no reputation, and reputation takes weeks rather than minutes to build.

Where to go next

Once a single send works, the two things worth doing before production are a webhook so you learn about bounces without polling, and a template so your message bodies stop living inside your application code.