---
title: Email quickstart
description: Verify a sending domain, write a template, create a recipient and send your first message with notify.messages.create.
type: tutorial
product: email
summary: A domain verified, a template written and one message sent and read back.
updated: 2026-10-01
order: 1
---

This page sends one email with Notify. The recipient is a **test recipient**:
its message is rendered and captured on the Message record and never delivered,
so you can try the whole path without sending real mail.

<Prerequisites
	items={[
		'An account, and a project with an environment - see the platform start page',
		'A Sylphx key with the notify:read, notify:write and notify:send scopes, as SYLPHX_API_KEY',
		'A domain you can add DNS records to, for example mail.example.com',
	]}
/>

Below, `$ENV` is the environment name that `sylphx access whoami` returns, for
example `orgs/acme/projects/shop/envs/production`.

## 1. Add and verify the domain

```bash
sylphx notify mail-domains create \
  --parent "$ENV" \
  --spec.domain mail.example.com
```

The answer lists `status.dns_records`: the DKIM, SPF, return-path and DMARC
records to publish at your DNS provider. Publish them, then check them now
instead of waiting for the next sweep:

```bash
sylphx notify mail-domains verify "$ENV/mail_domains/<id>"
```

A domain sends only after its DKIM and SPF records verify.

## 2. Write a template

```bash
curl -X POST "https://api.sylphx.com/v1/$ENV/templates?template_id=welcome" \
  -H "Authorization: Bearer $SYLPHX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "template": {
      "spec": {
        "email": {
          "sender_address": "hello@mail.example.com",
          "sender_name": "Example",
          "subject": "Welcome",
          "text_body": "Welcome aboard."
        }
      }
    }
  }'
```

The From address must be on a verified domain.

## 3. Create a test recipient

```bash
curl -X POST "https://api.sylphx.com/v1/$ENV/recipients?recipient_id=ada" \
  -H "Authorization: Bearer $SYLPHX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"recipient": {"external_key": "user-123", "email_addresses": ["ada@example.com"], "test": true}}'
```

`test: true` marks the recipient as a test recipient. So is any address whose
local part carries `+sylphx_test`, such as `ada+sylphx_test@example.com`.

## 4. Send the message

<CodeTabs>
	<CodeTab
		label="CLI"
		language="bash"
		code={`sylphx notify messages send \\
  --parent "$ENV" \\
  --recipient "$ENV/recipients/ada" \\
  --topic onboarding \\
  --template "$ENV/templates/welcome"`}
	/>
	<CodeTab
		label="cURL"
		language="bash"
		code={`curl -X POST "https://api.sylphx.com/v1/$ENV/messages" \\
  -H "Authorization: Bearer $SYLPHX_API_KEY" \\
  -H "Content-Type: application/json" \\
  -d '{"message": {"recipient": "'"$ENV"'/recipients/ada", "topic": "onboarding", "template": "'"$ENV"'/templates/welcome"}}'`}
	/>
	<CodeTab
		label="TypeScript"
		language="ts"
		code={`import { Sylphx } from '@sylphx/sdk'

const sylphx = new Sylphx()
const { env } = await sylphx.access.whoami({})

const message = await sylphx.notify.messages.create({
  parent: env!,
  message: {
    recipient: \`\${env}/recipients/ada\`,
    topic: 'onboarding',
    template: \`\${env}/templates/welcome\`,
  },
})
console.log(message.state)`}
	/>
</CodeTabs>

Notify admits the message, checks suppression and the recipient's preferences
for the `topic`, and answers it with a `state`. For a test recipient the
rendered subject and bodies are on the message's `capture`. For a real
recipient, `deliveries` carries one entry per channel with its state and the
provider's receipt.

## 5. Read it back

```bash
sylphx notify messages get "$ENV/messages/<id>"
```

Send one to a real address by dropping `test` and using your own address, and
check `deliveries[].state` reach `delivered`. A message you no longer want sent
can be cancelled with `sylphx notify messages cancel` until its deliveries are
handed off.

<RelatedDocs
	links={[
		{
			href: '/docs/email',
			label: 'Email overview',
			description: 'The pieces, and what is not served.',
		},
		{
			href: '/docs/api/messages',
			label: 'The messages collection',
			description: 'Every method, field and example.',
		},
		{
			href: '/docs/api/templates',
			label: 'The templates collection',
			description: 'Versions, send limits and every channel.',
		},
	]}
/>
