Manage Email Providers

This page is the API reference for managing email providers — creating them, editing them in place, and rotating credentials. For how to actually send mail and turn on open/click tracking, see Transactional Email.

Temps lets you edit an existing email provider in place with a partial-update endpoint, PATCH /api/email-providers/{id}, and a matching Edit dialog in the console. Use it to rename a provider, change its region, enable or disable it, or rotate its credentials — without deleting and recreating the row. The key safety property: omitting a credential block leaves the stored secret untouched, so you can rename a provider or flip its active flag without re-typing API keys or SMTP passwords.

This applies to all three provider types: AWS SES, Scaleway, and generic SMTP. The previously disabled Edit dropdown item is now live for each of them.

How it works

A PATCH carries only the fields you want to change. Every field in the request body is optional, and any field you leave out keeps its current value. The endpoint enforces a few rules:

  • provider_type is immutable. There is no provider_type field on the update request — the encrypted credentials format is fixed at creation time. To switch a provider from, say, SES to SMTP, delete the row and create a new one.
  • Credentials are preserved unless you send them. If you omit the credential block, the encrypted blob stays byte-identical in the database. If you supply a credential variant, it is re-serialized, re-encrypted, and replaces the stored blob.
  • Only one credential block per update. Supplying more than one of ses_credentials, scaleway_credentials, or smtp_credentials is rejected with 400.
  • The credential block must match the existing provider_type. Sending SMTP credentials to an SES provider is rejected with 400 before it reaches the service layer.
  • Empty names are rejected. A name that trims to empty returns 400 (Provider name cannot be empty).

On success the endpoint returns 200 with the masked EmailProviderResponse (the credentials field is masked for display, never the raw secret).

Audit logging

A successful update emits an EMAIL_PROVIDER_UPDATED audit event only when something actually changed. The event records the names of the fields that changed (for example name, region, is_active, credentials) and never their values — so secrets and credential material never reach the audit log. (Creating a provider emits EMAIL_PROVIDER_CREATED.)

Request body

UpdateEmailProviderRequest — all fields optional. Omit a field to leave it unchanged.

FieldTypeNotes
namestringNew display name. Must not be empty.
regionstringCloud region. For SMTP this is informational; host/port carry the routing.
is_activebooleanEnable or disable the provider without deleting it.
ses_credentialsobjectReplace AWS SES credentials. Only valid when the provider is SES.
scaleway_credentialsobjectReplace Scaleway credentials. Only valid when the provider is Scaleway.
smtp_credentialsobjectReplace generic SMTP credentials. Only valid when the provider is SMTP.

There is no provider_type field — it cannot be changed.

Credential block fields

BlockFields
ses_credentialsaccess_key_id, secret_access_key
scaleway_credentialsapi_key, project_id
smtp_credentialshost, port, username (optional), password (optional), encryption (starttls / tls / none, default starttls), accept_invalid_certs (default false)

Examples

Assume an SES provider with ID 1.

Rename only (credentials preserved)

Sending just name leaves the stored AWS keys byte-identical.

Rename a provider

curl -X PATCH https://your-temps-instance.com/api/email-providers/1 \
  -H "Authorization: Bearer your-temps-api-key" \
  -H "Content-Type: application/json" \
  -d '{"name": "Production SES (EU)"}'

Change region and disable

Update region and toggle active

curl -X PATCH https://your-temps-instance.com/api/email-providers/1 \
  -H "Authorization: Bearer your-temps-api-key" \
  -H "Content-Type: application/json" \
  -d '{"region": "eu-west-1", "is_active": false}'

Rotate credentials

Supplying a credential block re-encrypts and replaces the stored secret. The variant must match the provider's type (here, SES).

Rotate SES keys

curl -X PATCH https://your-temps-instance.com/api/email-providers/1 \
  -H "Authorization: Bearer your-temps-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "ses_credentials": {
      "access_key_id": "AKIAIOSFODNN7EXAMPLE",
      "secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
    }
  }'

For an SMTP provider, rotate the password while keeping host/port:

Rotate SMTP password

curl -X PATCH https://your-temps-instance.com/api/email-providers/2 \
  -H "Authorization: Bearer your-temps-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "smtp_credentials": {
      "host": "email-smtp.eu-west-1.amazonaws.com",
      "port": 587,
      "username": "AKIAIOSFODNN7EXAMPLE",
      "password": "new-smtp-password",
      "encryption": "starttls"
    }
  }'

Successful response

200 OK — masked EmailProviderResponse

{
  "id": 1,
  "name": "Production SES (EU)",
  "provider_type": "ses",
  "region": "eu-west-1",
  "is_active": false,
  "credentials": { },
  "created_at": "2025-12-03T10:30:00Z",
  "updated_at": "2026-05-29T10:30:00Z"
}

In the console

The Edit dialog (on the Email Providers page) mirrors these rules:

  • The provider_type indicator is read-only — labelled as immutable, since it can't be changed.
  • Secret fields render blank with the helper text "Leave blank to keep current." Leave them empty to preserve the stored secret.
  • Only fields that diverge from the loaded state are sent on submit. If you change nothing, no request is sent.
  • For SMTP, the non-secret fields — host, port, encryption, and accept_invalid_certs — are prefilled from the masked GET response, so you only re-enter the password if you want to rotate it.

Errors and gotchas

SituationStatusDetail
Empty name400Provider name cannot be empty (service layer)
Credential block doesn't match provider_type400Credential block does not match existing provider type ({existing}) (rejected by the handler before the service layer)
More than one credential block supplied400Only one credential block (ses/scaleway/smtp) may be supplied per update
SMTP block with empty host or port == 0400smtp_credentials.host is required / smtp_credentials.port must be greater than 0
Provider ID not found404Provider not found
Missing key / wrong permission401 / 403Requires a valid key with EmailProvidersWrite

The update path is covered by a unit-test suite in temps-email exercising rename, no-op (nothing sent), empty-name rejection, type-mismatch rejection, credential rotation (the ciphertext changes), and credential preservation (the ciphertext is byte-identical when the caller omits the block).

Next steps

Was this page helpful?