# Send activation and onboarding emails with your agent

How do I send activation emails for my SaaS? Connect Sendocado to your agent, add signups from your app, and set live a welcome email and follow-ups that stop when users finish onboarding. An agent can follow this page from start to end.

Activation emails here are the emails that get a new user to use your product: a welcome, then follow-ups. They are not the email that verifies an address.

## What you build

- New users get a welcome email right away, a follow-up on day 3 and a check-in on day 7.
- A user who finishes onboarding gets no more of these emails.
- A user who replies leaves the campaign, and the reply lands in your Replies inbox.

## What you need

- A Sendocado account. Sign in once at https://sendocado.com/login with Google or an email link.
- An email provider account: Resend, Amazon SES, Postmark, SendGrid, Mailgun, an SMTP server or Gmail.
- Access to your DNS host, to add the records for your sending domain.
- Access to your product’s code, to add two API calls.

## 1. Connect your agent

In Claude Code, run this command, then type `/mcp` and sign in:

```sh Add the server
claude mcp add --transport http sendocado https://sendocado.com/api/mcp
```

Cursor, Claude and other clients: [Sendocado for agents](https://sendocado.com/agents).

## 2. Decide what “finished onboarding” means

Pick the one action after which a new user gets value, for example “connected their first project”. Your app tags the contact `activated` at that moment. Agent: ask the user for this action. Do not guess it.

## 3. Create the project and set the postal address

Call `create_project` with a name and a time zone, or `list_projects` if the user already has one. Then set the postal address with `update_project`, sending every field back. Marketing email cannot go out without the address: the law asks for it in every footer.

## 4. Connect the sender

Ask the user for the provider credentials. Test them with `check_sender`, which saves nothing, then save them with `update_sender`, with the From name and address people will see. Never invent credentials. Gmail connects in the app only, in the browser.

## 5. Verify the sending domain

`create_sending_domain` returns the DNS records for the domain of the From address. Show them to the user, who adds them at the DNS host. After that, `check_sending_domain` asks the provider again; Sendocado also checks every 10 minutes. DNS changes can take hours to show.

## 6. Add signups from your app

Your app makes one REST call when someone signs up, and one when they finish onboarding. Both use an API key from **Settings → API keys**, sent as a Bearer token.

At signup, create the contact with the tag `trial`:

```sh Create a contact at signup
curl -X POST "https://sendocado.com/api/v1/projects/$PROJECT_ID/contacts" \
  -H "Authorization: Bearer $SENDOCADO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "maya@example.com",
  "first_name": "Maya",
  "last_name": "Patel",
  "timezone": "Europe/London",
  "tags": ["trial"],
  "attributes": {
    "plan": "trial",
    "company": "Northwind"
  }
}'
```

At finished onboarding, send the same email to the batch route with the tag `activated`. The batch route creates or updates by email, adds tags and never removes them, so the contact keeps `trial` and gains `activated`. It takes up to 1,000 contacts. The sample below sends two; your app sends one, with its email and `"tags": ["activated"]`, `null` for the names and time zone, and `{}` for attributes:

```sh Add or update contacts
curl -X PUT "https://sendocado.com/api/v1/projects/$PROJECT_ID/contacts/batch" \
  -H "Authorization: Bearer $SENDOCADO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "contacts": [
    {
      "email": "maya@example.com",
      "first_name": "Maya",
      "last_name": null,
      "timezone": null,
      "tags": ["customer"],
      "attributes": {
        "plan": "pro"
      }
    },
    {
      "email": "leo@example.com",
      "first_name": "Leo",
      "last_name": "Martin",
      "timezone": "Europe/Paris",
      "tags": ["trial"],
      "attributes": {}
    }
  ]
}'
```

## 7. Create the campaign

Get the emails from the user first; do not invent the copy. Then call `create_campaign` with `is_stopped_on_reply` set to `true`, this audience and three steps:

```json Audience: tag has trial, tag has not activated
[
  {
    "filters": [
      { "type": "tag", "op": "has", "tag": "trial" },
      { "type": "tag", "op": "has_not", "tag": "activated" }
    ]
  }
]
```

- The welcome, with `delay_days` 0: it goes out when the contact joins.
- The follow-up, with `delay_days` 3: day 3.
- The check-in, with `delay_days` 4: day 7, because each delay counts from the step before.

`create_campaign` makes a draft. Nothing sends while it is a draft. A contact who gets the tag `activated` stops matching the audience and leaves the campaign.

## 8. Check it with the user

- `preview_audience` counts who matches now, with a few of them.
- `send_test_email` sends each email to the user’s own inbox.
- `get_campaign_readiness` lists what stands between the campaign and going live. An empty list means it can go live.

Show the user the emails and the count.

## 9. Set it live after the user says yes

Call `set_campaign_status` with `live`. Going live emails real people: every contact who matches joins at once, and new signups join within seconds.

## 10. Read the results

- `get_campaign_stats`, after a week: sends, opens, clicks and replies for each step.
- `list_replies`: what people wrote back.
- `get_send`: what happened to one email, and why it did not arrive.

## 11. Change an email later

Read the campaign with `get_campaign`, then call `update_campaign_step` on that one step. Never re-create a step to change it: its results stay with its id.

## What the agent cannot do here

- The first sign-in.
- Adding DNS records at the DNS host.
- Connecting Gmail.
- Paying for a plan.
