# Send email over HTTPS

> Send a test message from the Send tab, then send from your application with the send API and an API key.

Source: https://www.coritan.com/docs/mail/smtp-relay/send-with-the-api/

In the dashboard:

- /dashboard/mail/…/send: https://www.coritan.com/dashboard/mail

The *send API* takes a message as JSON over HTTPS and hands it to SMTP Relay, which signs it for your domain and delivers it as it does mail sent over SMTP. Use it where an SMTP connection is awkward, such as in a serverless function. Before you wire up an application, you can check a domain end to end by sending a test message from the **Send** tab.

## Before you begin

- A *verified* sending domain on the relay. Over SMTP a domain can send once its ownership check passes, but the send API waits until the domain shows `Verified`. See [Add a sending domain to SMTP Relay](/docs/mail/smtp-relay/add-a-sending-domain/).
- At least one [SMTP credential](/docs/mail/smtp-relay/credentials/) on the relay. The send API submits each message with one: a credential on the From address's domain when there is one, otherwise any active credential on the relay.
- A [send API key](/docs/mail/smtp-relay/api-keys/) for the application. The **Send** tab does not need one.

## Send a test message from the dashboard

1. In the dashboard, go to [**Email**](https://www.coritan.com/dashboard/mail), open the SMTP Relay service, then the **Send** tab.
2. In **From**, enter the part of the address before the @, such as `no-reply`, and choose a verified domain after it.
3. Optionally, enter a **From name**, such as `Example Billing`.
4. In **To**, enter up to 50 addresses, separated by commas or spaces.
5. Enter a **Subject** and a **Message**. The message is plain text.
6. In **Category**, leave **Service default** or choose **Transactional** or **Marketing**. See [Transactional and marketing mail](/docs/mail/smtp-relay/message-categories/).
7. Select **Send message**.

A toast says `Accepted for 1 recipient.`, and a green **Accepted for delivery** box links to the **Events tab**, where you can watch the message arrive. The test message counts towards the month's allowance like any other. When the relay refuses the message, a **Could not send the message** box shows one of the messages in [Troubleshooting](#troubleshooting).

## Send from your application

Post the message to `/mail/send` with the key in the `X-Api-Key` header:

```bash
curl -X POST https://api.coritan.com/api/v1/mail/send \
  -H "X-Api-Key: $MAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "receipts@example.com",
    "from_name": "Example Billing",
    "to": ["alex@example.com"],
    "subject": "Your receipt",
    "text": "Thanks for your order.",
    "html": "<p>Thanks for your order.</p>",
    "category": "transactional"
  }'
```

The dashboard's **API keys** tab shows the same endpoint on `www.coritan.com`. Both hosts answer it.

The body takes these fields. Only `from`, `to` and one of `text` or `html` are needed:

`from`
: The sender's address, 3–320 characters, on a verified domain of the relay. It is used as the envelope sender too. `from_address` is accepted as another name for it.

`from_name`
: Optional, up to 255 characters. The name shown next to the address.

`to`
: A list of 1–50 addresses.

`cc`
: Optional, a list of up to 50 addresses. A transactional message takes 50 recipients across `to` and `cc` together.

`subject`
: Optional, up to 998 characters. Empty when left out.

`text`
: The plain-text body, up to 5,000,000 characters.

`html`
: The HTML body, up to 10,000,000 characters. With `text` as well, the message carries both and the recipient's app picks one.

`reply_to`
: Optional, up to 320 characters. The address replies go to.

`headers`
: Optional, an object of extra headers, such as `{"X-Order-Id": "10492"}`. Only headers whose names start with `X-`, plus `List-Unsubscribe`, `List-Unsubscribe-Post`, `List-Id` and `Precedence`, are added; any other header is dropped without an error. A name can have up to 64 characters and a value is cut at 998.

`category`
: Optional, `transactional` or `marketing`. Left out, the message takes the relay's default category.

The send API has no field for attachments or blind copies, and it ignores fields it does not know, such as `bcc` or `attachments`. To send either, use [SMTP](/docs/mail/smtp-relay/credentials/). The whole message, as built, can be up to 25 MB.

We add `Date`, a `Message-ID` at your domain and an `X-Mail-Category` header that names the category we sent the message as.

## Read the answer

The answer is `202`: we accepted the message and queued it for delivery. It does not mean the message has arrived. Follow it on the [**Events** tab](/docs/mail/smtp-relay/events/) or with [webhooks](/docs/mail/smtp-relay/webhooks/).

A transactional message answers with the addresses we sent it to:

```json
{
  "accepted": ["alex@example.com"],
  "suppressed": [],
  "node": "mx1.mail-fra.coritan.com",
  "message_id": "<175890432171.2481.9311874401294517206@example.com>"
}
```

`accepted`
: The recipients we queued the message for.

`suppressed`
: The recipients we left out because they are on the relay's [suppression list](/docs/mail/smtp-relay/suppressions/). When every recipient is suppressed, nothing is sent, `accepted` is empty and `node` is `null`, and the answer is still `202`.

`node`
: The name of the mail server that took the message.

`message_id`
: The message's `Message-ID` header. Webhook events and receiving servers refer to the message by it.

## Send marketing mail

With `"category": "marketing"`, or no category on a relay whose default is marketing, the send API sends each address in `to` and `cc` its own copy, addressed to that person alone. Each copy carries `List-Unsubscribe` and `List-Unsubscribe-Post` headers with a link for that recipient, so receiving apps can show an unsubscribe button. [Transactional and marketing mail](/docs/mail/smtp-relay/message-categories/) explains what an unsubscribe does.

The answer counts the copies and lists each one:

```json
{
  "accepted": 2,
  "category": "marketing",
  "messages": [
    {
      "accepted": ["alex@example.com"],
      "suppressed": [],
      "node": "mx1.mail-fra.coritan.com",
      "message_id": "<175890432171.2481.9311874401294517206@example.com>"
    },
    {
      "accepted": ["sam@example.com"],
      "suppressed": [],
      "node": "mx1.mail-fra.coritan.com",
      "message_id": "<175890432172.2481.5170284763319902451@example.com>"
    }
  ]
}
```

Here `accepted` is a number, the copies we queued, where a transactional answer gives a list of addresses. A copy to a suppressed address appears in `messages` with an empty `accepted` and is not counted.

## Check your limits

Read what the relay may still send with the same key:

```bash
curl https://api.coritan.com/api/v1/mail/send/limits \
  -H "X-Api-Key: $MAIL_API_KEY"
```

The answer holds the relay's allowance and hourly limit, which [How SMTP Relay sending limits work](/docs/mail/smtp-relay/sending-limits/#with-the-api) describes field by field, and three more fields:

`sending_frozen`
: `true` while sending is paused for the relay.

`max_recipients`
: `50`, the most recipients one request can have.

`max_message_bytes`
: `26214400`, the largest message the send API builds, in bytes (25 MB).

Check `remaining` before a large batch: it is `null` when the relay has no monthly cap.

## Troubleshooting

`401` `X-Api-Key header required`
: The request has no `X-Api-Key` header. The send API does not read `Authorization`.

`401` `Invalid API key`
: The key is wrong or revoked, or the relay is not active. See [Create and revoke send API keys](/docs/mail/smtp-relay/api-keys/#troubleshooting).

`403` `API key cannot send`
: The key does not have the `send` ability. Keys you create on the **API keys** tab always have it, so create a new key.

`422` with a `detail` list
: A field is missing or out of range: no `from` or `to`, more than 50 addresses in `to` or `cc`, or a `category` other than `transactional` or `marketing`. Each item in `detail` names the field in `loc`.

`400` `Provide a text or html body`
: Add `text`, `html` or both.

`400` `At most 50 recipients per message`
: A transactional message has more than 50 addresses in `to` and `cc` together. Split it into several requests.

`400` `Message exceeds 25 MB`
: Shorten the message, or link to large content instead of putting it in the body.

`400` `example.org is not a domain on this service`
: The domain of `from` is not on the relay. Use an address on one of the relay's domains, or [add the domain](/docs/mail/smtp-relay/add-a-sending-domain/). A subdomain is a domain of its own: with only `send.example.com` on the relay, send from an address at `send.example.com`. Over SMTP, the From header can use `example.com` when your account also holds that domain, in Coritan DNS or on another mail service; the send API cannot.

`400` `example.com is not verified yet; publish its DNS records first`
: The domain is on the relay but not verified. Publish its records and verify it.

`400` `Create an SMTP credential on this service before sending through the API`
: The relay has no active SMTP credential. [Create one](/docs/mail/smtp-relay/credentials/#create-a-credential), or turn one back on.

`400` `Sending is paused on this service; contact support`
: Sending is paused for the relay. See [Sending reputation and deliverability](/docs/mail/smtp-relay/deliverability/).

`429` `Monthly allowance and its 12% buffer are used up; upgrade the plan to continue`
: Sending the request would take the relay past everything its plan allows this month. A free plan says `Monthly sending allowance reached; upgrade the plan to continue`. See [How SMTP Relay sending limits work](/docs/mail/smtp-relay/sending-limits/).

`400` `Rejected by mail engine:` followed by an SMTP reply
: The relay's mail server refused the message, and the reply after the colon says why. The replies it can give are listed under [SMTP credentials](/docs/mail/smtp-relay/credentials/#troubleshooting).

`400` `No mail node is available right now` or `400` `All mail nodes refused the connection:`
: We could not reach a mail server to take the message. Nothing was sent, so retry the request after a short wait.

`503` `Mail service unavailable`
: The relay's service could not be found on our side. Contact [support](/docs/support/conversations/) if it persists.

## Related

- [Create and revoke send API keys](/docs/mail/smtp-relay/api-keys/)
- [Transactional and marketing mail](/docs/mail/smtp-relay/message-categories/)
- [Look up message events](/docs/mail/smtp-relay/events/)
- [Mail Send API reference](/docs/api/reference/client/mail-send-api/)

## With the API

The **Send** tab posts to `/client/smtp-relay/{service_id}/messages`, which takes the same body and gives the same answers with an access token in place of an API key:

```bash
curl -X POST https://api.coritan.com/api/v1/client/smtp-relay/4812/messages \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"from": "no-reply@example.com", "to": ["alex@example.com"], "subject": "Test", "text": "Hello from SMTP Relay."}'
```

It answers `202` as above. A relay that is not active answers `409` `Service is not active`.

On a Mail Hosting service, `POST /client/mail/{service_id}/messages` answers `404` `Not an SMTP Relay service`. Mailboxes send through [a mail app or webmail](/docs/mail/mail-hosting/connect-a-mail-app/).

## API

- `POST /api/v1/mail/send`: Send (https://www.coritan.com/docs/api/reference/client/mail-send-api/#op-post-api-v1-mail-send)
- `GET /api/v1/mail/send/limits`: Limits (https://www.coritan.com/docs/api/reference/client/mail-send-api/#op-get-api-v1-mail-send-limits)
- `POST /api/v1/client/smtp-relay/{service_id}/messages`: Send message (https://www.coritan.com/docs/api/reference/client/mail/smtp-relay/#op-post-api-v1-client-smtp-relay-service-id-messages)
- `POST /api/v1/client/mail/{service_id}/messages`: Send message (https://www.coritan.com/docs/api/reference/client/mail/mail/#op-post-api-v1-client-mail-service-id-messages)
