# Send over SMTP with credentials

> Create an SMTP credential for an application, connect it to the relay on port 587 or 465, and rotate, disable or revoke it.

Source: https://www.coritan.com/docs/mail/smtp-relay/credentials/

In the dashboard:

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

An *SMTP credential* is a username and password that an application uses to sign in to SMTP Relay. Create one for each application, so that you can rotate or revoke one without touching the others. The [send API](/docs/mail/smtp-relay/send-with-the-api/) also sends through a credential, so a relay needs at least one even if you only send over HTTPS.

## Before you begin

- An SMTP Relay service with the status `active`. While the service is being set up, **Create credential…** is greyed out.
- A domain on the relay whose ownership check has passed. See [Add a sending domain to SMTP Relay](/docs/mail/smtp-relay/add-a-sending-domain/).
- Room for another credential. A relay holds up to 200. When its plan sets a lower limit, the **SMTP credentials** card shows it, such as `2 of 5 on this plan.`

## Create a credential

1. In the dashboard, go to [**Email**](https://www.coritan.com/dashboard/mail), open the SMTP Relay service, then the **Credentials** tab.
2. Select **Create credential…**.
3. In **Domain**, choose the domain the application sends from. A domain that is not verified yet shows `(pending)` after its name.
4. In **Label**, name the application, such as `billing app`. Leave it empty and the label is `default`.
5. Select **Create credential**.
6. Copy the **Username** and **Password** from the dialog, or select **Copy all**, and store them where the application keeps its secrets. We show the password only this once.
7. Select **I have saved them**.

The username is built from the label and the domain: the label in lower case with anything other than letters and digits turned into hyphens, cut to 24 characters, then a hyphen and six random characters. A credential labelled `billing app` on `example.com` gets a username such as `billing-app-3f9a1c@example.com`. The password has 32 characters.

## Connect your application

Give the application these settings. The **SMTP endpoint** card on the **Credentials** tab shows the host for your relay.

| Setting | Value |
| --- | --- |
| Host | The **Host** on the **SMTP endpoint** card, such as `smtp.mail-fra.coritan.com` |
| Port and security | `587` with STARTTLS, or `465` with implicit TLS (often called SSL/TLS) |
| Authentication | `PLAIN` or `LOGIN` |
| Username | The credential's full username, such as `billing-app-3f9a1c@example.com` |
| Password | The credential's password |
| From address | Any address on a domain of this relay, such as `receipts@example.com` |

The From address does not have to be on the credential's own domain: one credential can send for every domain on the relay. To send a message as marketing mail, add the header `X-Mail-Category: marketing`; see [Transactional and marketing mail](/docs/mail/smtp-relay/message-categories/).

To test the credential from a terminal, write a message to a file:

```text title="message.txt"
From: Receipts <receipts@example.com>
To: alex@example.com
Subject: Test from SMTP Relay

This message came through SMTP Relay.
```

Then send it with `curl`, which upgrades the connection with STARTTLS:

```bash
curl --url "smtp://smtp.mail-fra.coritan.com:587" --ssl-reqd \
  --user "billing-app-3f9a1c@example.com:$SMTP_PASSWORD" \
  --mail-from "receipts@example.com" \
  --mail-rcpt "alex@example.com" \
  --upload-file message.txt
```

In application code, use your language's SMTP library. With Python's standard library:

```python
import os
import smtplib
from email.message import EmailMessage

msg = EmailMessage()
msg["From"] = "Receipts <receipts@example.com>"
msg["To"] = "alex@example.com"
msg["Subject"] = "Your receipt"
msg.set_content("Thanks for your order.")

with smtplib.SMTP("smtp.mail-fra.coritan.com", 587) as smtp:
    smtp.starttls()
    smtp.login("billing-app-3f9a1c@example.com", os.environ["SMTP_PASSWORD"])
    smtp.send_message(msg)
```

## Result

- The credential is listed on the **Credentials** tab with its label, its username, when its password was set and its **Enabled** switch on.
- The application's messages go out signed for your domain, and each one appears on the [**Events** tab](/docs/mail/smtp-relay/events/).

## Rotate a password

Rotate a credential's password when it may have leaked, or on a schedule.

1. On the **Credentials** tab, open the menu at the end of the credential's row and select **Rotate password…**.
2. Select **Rotate password** to confirm. The old password stops working at once.
3. Copy the new **Password** from the dialog, then select **I have saved them**.
4. Put the new password in the application straight away.

The new password has 24 characters. The **Password set** column shows when it changed. To give a credential a password you choose, use the API: see [With the API](#with-the-api).

## Turn a credential off or on

Turning a credential off stops it signing in but keeps its username and password, so you can turn it back on later.

1. On the **Credentials** tab, find the credential.
2. Use the switch in its **Enabled** column. A toast confirms the change, such as `billing-app-3f9a1c@example.com disabled.`

## Revoke a credential

> [!CAUTION]
> Revoking deletes the credential and its password. Any application still using it is refused from then on, and a new credential gets a different username. To pause a credential instead, turn it off.

1. On the **Credentials** tab, open the menu at the end of the credential's row and select **Revoke credential…**.
2. Type the credential's username to confirm, then select **Revoke credential**.

The send API needs an active credential. It uses one on the From address's domain when there is one, and otherwise any active credential on the relay, so revoke the last one only when nothing sends through the relay.

On an [internal mail tenant](/docs/mail/internal-tenants/), the credential the platform sends its own mail with can be rotated but not turned off or revoked: **Revoke credential…** shows **Staff only**.

## Troubleshooting

`Prove you own example.com first: publish the ownership record shown under Domains, then check the domain`
: The domain's ownership check has not passed yet. Publish the ownership record and select **Verify now** on the domain's page. See [Add a sending domain to SMTP Relay](/docs/mail/smtp-relay/add-a-sending-domain/#publish-the-records).

`A relay may hold at most 200 SMTP credentials; remove one you no longer use` or `This plan allows 5 SMTP credentials`
: The relay holds as many credentials as it can. Revoke one you no longer use. Several applications can share a credential, but you then rotate them together.

`The domain is not registered in the mail engine yet; check the domain again in a minute`
: The domain's ownership check passed moments ago and we are still setting it up. Select **Verify now** on the domain's page, then create the credential again.

`Service is not active`
: The service is suspended or not set up yet. Its status is on the **Overview** tab.

The application says the username or password is wrong
: Use the whole username, including the six random characters before the @, and the password from when you created or last rotated the credential. A credential that is turned off cannot sign in, and while sending is paused for the relay, no credential can: the panel then shows **Sending is paused**. After 30 failed sign-ins in an hour from one IP address, the relay refuses that address for 24 hours, so fix the password before the application retries many times.

The application cannot sign in when its settings are a URL
: Some frameworks take the settings as one URL, such as `smtp://user:password@host:587`. The username contains an @, and passwords can contain `@`, `#`, `%`, `?`, `+` and `=`, so percent-encode both, or pass the username and password as separate settings.

`550 5.7.1 Sender domain example.org is not verified on this account`
: The envelope sender, the address the application gives in `MAIL FROM`, is not on a domain of this relay whose ownership has been proved. Send from an address on one of the relay's domains.

`550 5.7.1 From address must use a verified domain, not example.org`
: The `From` header is on a domain the relay has not proved. Change the From address, or [add the domain](/docs/mail/smtp-relay/add-a-sending-domain/).

`550 5.7.1 Sending is not available for this account`
: The credential is turned off, or the relay is not active. Turn the credential on, or check the relay's status on the **Overview** tab.

`550 5.7.1 Sending is paused for this account; contact support`
: Sending is paused for the relay: its bounce or complaint rate passed our limit, or our staff paused it. See [Sending reputation and deliverability](/docs/mail/smtp-relay/deliverability/).

`550 5.7.1 Monthly allowance and its 12% buffer are used up; upgrade the plan to continue`
: The relay has sent 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/).

`550 5.1.1 Recipient alex@example.com is suppressed after a bounce or complaint`
: The address is on the relay's suppression list. See [Manage the suppression list](/docs/mail/smtp-relay/suppressions/).

`550 5.7.1 This login is not a mail account we know`
: The credential belongs to a relay that no longer exists. Create a credential on an active relay.

The application cannot connect
: Check the host and the port. Port `587` needs STARTTLS and port `465` needs TLS from the start, so an application that uses the wrong security for the port cannot connect. Use port `587` or `465`: many networks block port `25`.

A large message is refused
: SMTP accepts messages up to 50 MB, including the encoded attachments, which are about a third larger than the files. The send API takes up to 25 MB.

## Related

- [Add a sending domain to SMTP Relay](/docs/mail/smtp-relay/add-a-sending-domain/)
- [Send email over HTTPS](/docs/mail/smtp-relay/send-with-the-api/)
- [Transactional and marketing mail](/docs/mail/smtp-relay/message-categories/)
- [How SMTP Relay sending limits work](/docs/mail/smtp-relay/sending-limits/)

## With the API

Create a credential:

```bash
curl -X POST https://api.coritan.com/api/v1/client/smtp-relay/4812/credentials \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"domain_id": 311, "label": "billing app"}'
```

The body takes these fields:

`domain_id`
: The domain the username goes on, from `GET /client/smtp-relay/{service_id}/domains`. Its ownership check must have passed.

`label`
: Optional, 1–100 characters, `default` when left out. It names the credential in lists and starts its username.

The answer is `201` with the credential, its `password`, shown this once, and `smtp`, the host names to connect to:

```json
{
  "id": 7731,
  "tenant_id": 903,
  "domain_id": 311,
  "kind": "relay_credential",
  "address": "billing-app-3f9a1c@example.com",
  "local_part": "billing-app-3f9a1c",
  "display_name": "billing app",
  "quota_bytes": 0,
  "targets": [],
  "status": "active",
  "password_set_at": "2026-09-16T10:52:03.418207+00:00",
  "created_at": "2026-09-16T10:52:03.418207+00:00",
  "totp_enabled": false,
  "app_passwords": 0,
  "frozen_reason": null,
  "user_id": null,
  "password": "Vq8#nT2mLw!4Rz=Kp7Xc9@Hd3Fs+Gy6J",
  "smtp": {
    "smtp_host": "smtp.mail-fra.coritan.com",
    "imap_host": "imap.mail-fra.coritan.com",
    "jmap_host": "jmap.mail-fra.coritan.com",
    "mx_hostname_base": "mail-fra.coritan.com",
    "webmail_url": "https://jmap.mail-fra.coritan.com",
    "display_name": null,
    "support_url": null,
    "postmaster_address": null,
    "user_mailbox_domain": null
  }
}
```

The username is `address`, and the label is `display_name`. Connect to `smtp.smtp_host`.

The other operations:

| Operation | Body | Answer |
| --- | --- | --- |
| `GET /client/smtp-relay/{service_id}/credentials` | | `{"items": [...], "smtp": {...}}`: each credential as above with `locked` in place of `password`, and the host names |
| `POST /client/smtp-relay/{service_id}/credentials/{account_id}/rotate` | | `{"id", "address", "password"}` with a new 24-character password |
| `PATCH /client/smtp-relay/{service_id}/credentials/{account_id}/enabled` | `{"enabled": false}` | The credential, with `status` `disabled` or `active` |
| `DELETE /client/smtp-relay/{service_id}/credentials/{account_id}` | | `{"ok": true}` |

`locked` is `null` on your own services. On an internal mail tenant it holds `The platform sends its own mail with this credential. You can rotate it, but only staff can disable or delete it.`, and turning that credential off or revoking it answers `409` with the same message.

To give a credential a password you choose, 12–128 characters, post it to the credential's id under `mailboxes`:

```bash
curl -X POST https://api.coritan.com/api/v1/client/smtp-relay/4812/mailboxes/7731/password \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"password": "a-long-passphrase-you-chose"}'
```

The answer is `{"id", "address", "password"}` with the password you sent. The send API goes on working after a rotation or a new password, because it always uses the current one.

A refused request answers `400` with one of the messages in [Troubleshooting](#troubleshooting), or `Domain not found on this service` for a `domain_id` that is not on the relay. An id that is not a credential of the relay answers `404` `Not found`, a value outside a field's range answers `422`, and a failure on our side answers `502` with a message that starts `Mail engine error:`.

### On a Mail Hosting service

The same paths exist under `/client/mail/{service_id}/credentials`, where they do this:

- `GET` answers `{"items": [], "smtp": {...}}`: no credentials, and the service's host names.
- `POST` answers `404` `Not an SMTP Relay service`.
- `.../{account_id}/rotate` and `.../{account_id}/enabled` accept a mailbox's id and act on the mailbox. `rotate` works as `POST .../mailboxes/{account_id}/password` with `{}`: it sets a generated password and turns off two-factor sign-in. See [Mailboxes](/docs/mail/mail-hosting/mailboxes/#with-the-api).
- `DELETE .../{account_id}` answers `404` `Not found`.

## API

- `GET /api/v1/client/smtp-relay/{service_id}/credentials`: List credentials (https://www.coritan.com/docs/api/reference/client/mail/smtp-relay-credentials/#op-get-api-v1-client-smtp-relay-service-id-credentials)
- `POST /api/v1/client/smtp-relay/{service_id}/credentials`: Create credential (https://www.coritan.com/docs/api/reference/client/mail/smtp-relay-credentials/#op-post-api-v1-client-smtp-relay-service-id-credentials)
- `DELETE /api/v1/client/smtp-relay/{service_id}/credentials/{account_id}`: Delete credential (https://www.coritan.com/docs/api/reference/client/mail/smtp-relay-credentials/#op-delete-api-v1-client-smtp-relay-service-id-credentials-account-id)
- `PATCH /api/v1/client/smtp-relay/{service_id}/credentials/{account_id}/enabled`: Credential enabled (https://www.coritan.com/docs/api/reference/client/mail/smtp-relay-credentials/#op-patch-api-v1-client-smtp-relay-service-id-credentials-account-id-enabled)
- `POST /api/v1/client/smtp-relay/{service_id}/credentials/{account_id}/rotate`: Rotate credential (https://www.coritan.com/docs/api/reference/client/mail/smtp-relay-credentials/#op-post-api-v1-client-smtp-relay-service-id-credentials-account-id-rotate)
- `GET /api/v1/client/mail/{service_id}/credentials`: List credentials (https://www.coritan.com/docs/api/reference/client/mail/mail-credentials/#op-get-api-v1-client-mail-service-id-credentials)
- `POST /api/v1/client/mail/{service_id}/credentials`: Create credential (https://www.coritan.com/docs/api/reference/client/mail/mail-credentials/#op-post-api-v1-client-mail-service-id-credentials)
- `DELETE /api/v1/client/mail/{service_id}/credentials/{account_id}`: Delete credential (https://www.coritan.com/docs/api/reference/client/mail/mail-credentials/#op-delete-api-v1-client-mail-service-id-credentials-account-id)
- `PATCH /api/v1/client/mail/{service_id}/credentials/{account_id}/enabled`: Credential enabled (https://www.coritan.com/docs/api/reference/client/mail/mail-credentials/#op-patch-api-v1-client-mail-service-id-credentials-account-id-enabled)
- `POST /api/v1/client/mail/{service_id}/credentials/{account_id}/rotate`: Rotate credential (https://www.coritan.com/docs/api/reference/client/mail/mail-credentials/#op-post-api-v1-client-mail-service-id-credentials-account-id-rotate)
