Skip to content
Avanet

Automate Sophos Email S/MIME through the API

The Sophos Email Management API can control the complete S/MIME certificate lifecycle. The safe sequence is: read the inventory, create or upload exactly one internal tenant CA, initially create the tenant configuration in a disabled state, provision trust and external recipient certificates, enable S/MIME, provision internal user certificates, and then test mail flow. This article deliberately separates the internal tenant CA, trusted external CAs, internal user certificates, and external recipient certificates. They use different paths and are not interchangeable.

For architecture, policy, and UI tests, see the S/MIME GUI guide. The Sophos Email Management API introduction explains the general API contract; OAuth2, tenant resolution, and regional host discovery are covered by the planned API authentication and tenant-routing runbook.

Critical warning: DELETE /smime/config/{deleteToken} deletes all S/MIME certificates and private keys for the tenant and sets smimeEnabled to false. It is not a certificate rotation mechanism or routine troubleshooting step. The API documents no private-key export. Without separately retained, authorized PKCS#12 sources, keys and the ability to decrypt historical content can be lost permanently.

Prerequisites and a safe request base

Bring forward only these validated values from the authentication workflow:

  • SOPHOS_ACCESS_TOKEN: short-lived bearer token;
  • SOPHOS_TENANT_ID: target tenant UUID;
  • SOPHOS_API_HOST: complete regional host for that tenant.

The reviewed specification is Email Management API v1.4.0. Recheck the current specification before every implementation. All paths below are relative to the regional /email/v1 base and require Authorization: Bearer ***, X-Tenant-ID, and, for JSON requests, Content-Type: application/json:

EMAIL_API_HOST="${SOPHOS_API_HOST%/}/email/v1"

Tokens, deleteToken, PKCS#12 passwords, PKCS#12 content, and private keys must not enter command-line arguments, source code, ordinary logs, or tickets. Use mode-600 files, an approved secret store, and cleanup of temporary files. The examples use ops@example.net and alice@example.net; replace both with approved addresses for the target tenant.

Before the first write, run these three read tests and record only HTTP status, requestId/correlationId on errors, and the schema result:

GET /smime/config
GET /smime/ca/internal
GET /smime/users/internal?pageSize=1

A 404 from the first two reads means the configuration or internal CA does not yet exist. It is a state, not a reason to guess paths. Lists return items and pages; URL-encode pages.nextKey as pageFromKey on the next request until no nextKey remains.

Provision the internal tenant CA

The internal CA signs certificates generated by Sophos for internal users. A tenant can have exactly one internal CA. Both creation and upload automatically create a disabled S/MIME configuration if necessary, but neither enables S/MIME. A second attempt returns 409; the reviewed API has no separate path to delete or replace only this CA.

Option A: have Sophos generate the CA

POST /smime/ca/internal requires organizationName, locality, country, and email. country is exactly two uppercase ISO 3166-1 letters. organizationUnit is optional, as is either certExpiryDate in YYYY-MM-DD format or certValidityPeriod from 1 to 20 years. The default is 20 years; if both are supplied, the API uses the shorter period.

{
  "organizationName": "Example Operations GmbH",
  "organizationUnit": "Messaging",
  "locality": "Zurich",
  "country": "CH",
  "email": "ops@example.net",
  "certValidityPeriod": 10
}

Success is 201. Retain the returned 64-character SHA-256 fingerprint, issuer, validFrom, expiresAt, and origin without needlessly logging the complete response.

Option B: upload an existing CA and key

POST /smime/ca/internal/certificate expects a Base64-encoded PKCS#12 certificate-key bundle, not PEM:

{
  "pkcs12": "<BASE64_PKCS12>",
  "password": "<PKCS12_PASSWORD>"
}

After Base64 encoding, pkcs12 must contain 1200 to 24000 characters; password must contain 3 to 50 characters. Before the request, the PKI owner validates the certificate, private key, chain, purpose, and password. Base64 is transport encoding, not protection for a private key. Remove line breaks from Base64 output and never place PEM text in pkcs12.

Validate either option independently:

  1. GET /smime/ca/internal returns metadata and the same fingerprint.
  2. GET /smime/ca/internal/certificate returns the public CA certificate as PEM with application/octet-stream.
  3. The downloaded PEM fingerprint matches the change inventory. The file does not contain a recoverable CA private key.

Enable the tenant configuration only afterwards

GET /smime/config returns smimeEnabled, extractCertificate, up to five certExpiryNotificationEmailAddresses, and the eight-character deleteToken. Treat that token as a destructive secret.

If the precheck still finds no configuration, create it with POST /smime/config. smimeEnabled is required and extractCertificate defaults to false:

{
  "smimeEnabled": false,
  "extractCertificate": false,
  "certExpiryNotificationEmailAddresses": ["ops@example.net"]
}

Use PATCH /smime/config for an existing configuration. At least one field is required; omitted fields remain unchanged. On PATCH, null or [] clears all notification addresses and duplicates are removed. The safe rollout is:

  1. Write the configuration with smimeEnabled: false and confirm it with GET.
  2. Provision and inventory trusted CAs and external pilot certificates.
  3. Only then send {"smimeEnabled":true} to PATCH /smime/config. Without an internal CA, the API returns 409.
  4. Confirm smimeEnabled: true with GET, create or upload internal pilot certificates, and run signing and encryption tests.

extractCertificate: true permits extraction from inbound messages. Functional prerequisites, especially signature verification in the Secure Message policy, remain as described in the GUI guide; the API switch alone does not make a certificate trusted.

Manage trusted external CAs

This list contains additional issuers used to verify signed messages. It is neither the internal tenant CA nor a user certificate. Before upload, check in Sophos Fusion (formerly Sophos Central) whether the issuer is already globally trusted and verify its SHA-256 fingerprint over an independent channel.

  • GET /smime/cas/external lists metadata. Filters are commonName, certValidBefore, certValidAfter, certExpiryBefore, certExpiryAfter, certFingerprint, issuerCN, pageFromKey, and pageSize (default 50).
  • POST /smime/cas/external/certificate uploads a PEM CA string in certificate. The field is 300 to 32000 characters including header and footer.
  • GET /smime/cas/external/certificate/{fingerprint} downloads that exact PEM.
  • DELETE /smime/cas/external?certFingerprint=... deletes that exact trust entry.
{
  "certificate": "-----BEGIN CERTIFICATE-----\n<BASE64_CERTIFICATE>\n-----END CERTIFICATE-----"
}

Uploading an identical certificate returns 409. Before DELETE, an exact list read with certFingerprint must return exactly the expected item. After 200 and deleted: true, the same filter must be empty; then test a signature through the remaining trust chain.

Manage external recipient certificates

External user certificates are public certificates belonging to communication partners. They contain no tenant private key. POST /smime/users/external/certificate accepts a PEM string in certificate (300 to 32000 characters), derives identity from the certificate, and enables S/MIME for that external user:

{
  "certificate": "-----BEGIN CERTIFICATE-----\n<BASE64_CERTIFICATE>\n-----END CERTIFICATE-----",
  "confirmVerificationOnlyCert": false
}

For a DSA or EC certificate, confirmVerificationOnlyCert: true must acknowledge the intentional signing/verification-only restriction; it cannot then be used for encryption/decryption. An identity can have at most two certificates (422 on the next upload); a duplicate returns 409.

  • GET /smime/users/external?email=partner@example.net filters by exact address. It also supports emailStartsWith, the date, fingerprint, and issuer filters, and pageFromKey/pageSize described above.
  • GET /smime/users/external/certificate/{fingerprint} downloads PEM by its 64-character SHA-256 fingerprint.
  • DELETE /smime/users/external?email=...&certFingerprint=... deletes only the exact address/fingerprint pair. URL-encode the parameters. Deleting the last certificate implicitly removes the user from the S/MIME list.

After upload, exact email address, fingerprint, issuer, and validity must match the list read. Only then use a pilot policy to send an encrypted message and have the intended partner decrypt it.

Create or upload internal user certificates

Internal users must exist as matching tenant identities. API create or upload enables S/MIME for the user. Do not normalize addresses in automation: reuse the exact email returned by GET for filters and deletions.

To have Sophos generate a certificate, send POST /smime/users/internal:

{
  "email": "alice@example.net",
  "certValidityPeriod": 3
}

Only email is required. The same optional certExpiryDate or certValidityPeriod rules from 1 to 20 years apply as for the internal CA. An internal CA and enabled/configured S/MIME are prerequisites.

To use an existing key, send POST /smime/users/internal/certificate:

{
  "email": "alice@example.net",
  "pkcs12": "<BASE64_PKCS12>",
  "password": "<PKCS12_PASSWORD>",
  "confirmSigningOnlyCert": false
}

email, pkcs12, and password are required. The limits are again 1200 to 24000 Base64 characters and 3 to 50 password characters. DSA/EC requires confirmSigningOnlyCert: true and is then suitable only for signing/verification, not encryption/decryption. If the bundle contains CA certificates, Sophos also stores them as trusted CAs; validate every included chain beforehand and inspect /smime/cas/external afterwards. Each internal user can have at most two certificates; duplicates return 409 and a third certificate returns 422.

  • GET /smime/users/internal?email=alice@example.net returns the exact user and certificates. Further filters are userName, emailStartsWith, date, fingerprint, and issuer filters, plus pagination.
  • GET /smime/users/internal/certificate/{fingerprint} downloads PEM. For an uploaded bundle, the download also includes CA certificates uploaded with it, but no private key.
  • DELETE /smime/users/internal?email=...&certFingerprint=... deletes only that pair. The user disappears from the S/MIME list when the last certificate is deleted.

After every create or upload, confirm 201, exact address, expected fingerprint, issuer, and expiry. Then test outbound signing and inbound decryption with the intended Secure Message policy.

Perform the destructive reset only as an approved rebuild

Approval required: Run this workflow only with explicit change approval. Consequence: the internal CA, trusted CAs, internal and external user certificates, and every stored private key are deleted; smimeEnabled becomes false. It cannot repair one object selectively.

The precheck and approval evidence must include:

  1. Fully inventory GET /smime/config, /smime/ca/internal, /smime/cas/external, /smime/users/internal, and /smime/users/external across all pages.
  2. For every recoverable key object, confirm an authorized PKCS#12 source and tested password recovery. PEM downloads are not private-key backups.
  3. Record policy scope, maintenance window, owner, communication partners, expected outage, and complete rebuild order.
  4. Obtain the current deleteToken directly from GET /smime/config, never from old logs or tickets.
  5. Have a second authorized person verify tenant ID, inventory, consequence, and token association.

Only then call exactly DELETE /smime/config/{deleteToken}. A mismatched token returns 409; a missing configuration returns 404. On timeout, 5xx, or an unknown result, do not retry blindly: first read GET /smime/config and every inventory endpoint to establish the server-side effect. Success requires 200 and deleted: true; afterwards the configuration must be absent or rebuilt with smimeEnabled: false. Rebuild in the same order: internal CA, disabled configuration, trust, users, then final enablement.

Validation and troubleshooting

An API response alone does not prove working S/MIME mail flow. Validate both layers after changes:

  1. API state: GET readback through the exact path; check email, 64-hex-character SHA-256 fingerprint, issuer, validFrom, expiresAt, origin, end of pagination, and configuration.
  2. Message effect: with a small Secure Message pilot policy, sign outbound, verify inbound, encrypt to the external pilot, and decrypt for the internal pilot. Record message ID, UTC time, and result, but no keys or complete certificate payloads.

Diagnose common failures as follows:

  • 400: check JSON field names, PEM header/footer, Base64 without line breaks, PKCS#12 password, lengths, date format, and email syntax. Process individual errors in validation responses.
  • 401/403: check token, minimum permission, and tenant assignment; never guess the region or tenant.
  • 404: first check regional host, exact path, email/fingerprint pair, and object inventory.
  • 409: internal CA or certificate already exists, internal CA is missing during enablement, or deleteToken does not match. Read state instead of repeating the write.
  • 422: the user already has two certificates. Do not work around it by deleting an unknown fingerprint.
  • Unexpected list result: fetch all pages through pages.nextKey, URL-encode pageFromKey, and use exact rather than prefix filters.
  • Signing or encryption fails despite correct GET: inspect tenant enablement, policy scope/order, certificate validity, exact identity, trust chain, and key usage. The GUI guide contains the complete message test.

For escalation, method, path without sensitive query values, HTTP status, UTC time, requestId/correlationId, tenant ID, expected object type, and anonymized certificate metadata are sufficient. Exclude bearer tokens, deleteToken, passwords, PKCS#12, private keys, and complete personal lists.