# Send a message

> Part of the Cowliss docs. Markdown for every page: append `index.md` to its URL. Site map: /llms.txt

## An inline body

```ts
const { data, error } = await resend.emails.send({
  from: "Acme Billing <invoices@mail.example.com>",
  to: ["ada@acme-demo.io"],
  subject: "Your receipt",
  html: "<p>Thanks for your order.</p>",
});

data?.id; // dlv_… the delivery this send left behind
```

`from` is required, exactly as Resend requires it, and has to be on a domain you verified. See [Sending and delivery](/emails/delivery/).

`to`, `cc`, `bcc` and `reply_to` each take one address or a list, `headers` are passed on, and `tags` are accepted and dropped, because Cowliss labels a delivery by its own fields.

Every send is checked against your credit and your suppression list first. An address that has bounced or complained is dropped from the message; if that leaves nobody, the call still answers with an id and the delivery records that it was suppressed.

## A template you pushed

`template` names a template key, `variables` are its props:

```ts
await resend.emails.send({
  to: ["ada@acme-demo.io"],
  template: { id: "vip-order", variables: { orderId: "A-2291" } },
});
```

The key is looked up in the app the source belongs to, so another app's template of the same key is never used. The template writes the whole message, so a `subject`, `html` or `text` beside it is refused: a message either names a template or writes its own body. The props are checked by the template itself, exactly as they are when you press **Send test** on its page. See [Email templates](/emails/).

Only a template sent as bare `transactional` can be sent this way. One its recipients can turn off, any `marketing.<name>` or `transactional.<name>`, is refused, because an address is nobody's profile, so there is nobody's answer to check. Send those from an automation, or with [`cow.emails.send`](/sdk/emails/) addressed to a profile.

The delivery records the template key, so a template's page shows what your code sent beside what your automations sent.

## Test addresses

Resend's test addresses work unchanged: `delivered@resend.dev`, `bounced@resend.dev` and `complained@resend.dev` are real sends that end as their name says, so code ported from Resend keeps its tests. Cowliss's own set, with `suppressed@` as well, is in [Testing a send](/sdk/emails/#testing-a-send).

## Read a message back

```ts
const { data } = await resend.emails.get("dlv_…");
```

You get Resend's email object: the id, the provider's `message_id`, the addresses, the subject, when it was created, and `last_event`. Cowliss keeps no rendered bodies, so `html` and `text` are always `null`, `scheduled_at` is `null`, and `tags` is empty.

| Where the message got to | `last_event` |
| --- | --- |
| Handed over | `sent` |
| Accepted by the recipient's mail server | `delivered` |
| Rejected | `bounced` |
| Marked as spam | `complained` |
| Stopped before it went, or failed on the way | `failed` |
