DEV Community

CloudveilElenor12
CloudveilElenor12

Posted on

GDPR Evidence Comparison for Transactional Email APIs on European Custom Domains

Short answer: compare welcome-email APIs by the evidence they let you produce, not by the number of sending features. For a European e-commerce signup, the useful record proves which verification template was sent, from which authenticated domain, at what time, and what happened next. It should not preserve the full address and message body in every log line.

That is the boundary.

The cost problem is mostly a retention problem. Every accepted signup can create a request log, a provider response, a delivery event, a retry record, and an audit record. At 100,000 signups, with two delivery attempts per signup, that is already 200,000 attempt records before opens, bounces, and support queries are counted. The dominant term is usually the repeated payload and its labels, not the one-time configuration of a sending API.

How do you compare transactional email APIs for a GDPR welcome flow?

Start with an evidence contract. For each verification link, retain a pseudonymous account identifier, event time in UTC, template revision, authenticated sender-domain identifier, destination region as a coarse value, request outcome, provider message identifier, and the reason for any retry. Keep the verification token outside telemetry. A token is both a credential and an unnecessary liability in an observability system.

The audit record can be small:

{
  "event": "verification_email.accepted",
  "account_ref": "hmac:7c2b...",
  "template_ref": "signup-v4",
  "sender_domain": "mail.example.eu",
  "region": "EU",
  "attempt": 1,
  "provider_message_ref": "opaque-id",
  "occurred_at": "2026-10-28T09:30:00Z"
}
Enter fullscreen mode Exit fullscreen mode

A keyed digest makes correlation possible without making the raw address a default search key. It is not anonymization: the key, retention period, access policy, and re-identification risk still matter. That distinction belongs in the data inventory and in the control review.

The sending interface should return an opaque message reference, while the application owns the state transition from pending to verified or expired. That separation prevents a provider dashboard from becoming the system of record. It also makes a comparison fair: test the same template, domain, timeout, retry policy, and evidence contract against every candidate. A team that skips this step can mistake a polished dashboard for a compliance control, then discover during an access request that the dashboard retained an address but not the template revision or sender-domain result. That is a poor exchange: more personal data, less useful evidence.

How should retention change the telemetry bill?

Retention math is more useful than a headline price. Suppose one structured event averages 900 bytes after serialization and indexing adds another 1.1 times the event size. A stream of 200,000 attempt events would be about 180 MB of raw event data, or roughly 378 MB with that stated indexing assumption. Those figures are an illustrative calculation, not a production benchmark.

Now add a full HTML body, a recipient address, and a verbose provider response to every attempt. The arithmetic changes before traffic does. The remedy is not to delete the evidence needed for an audit; it is to stop storing the same evidence in three systems. Keep a compact, access-controlled audit row for the decision, short-lived operational logs for debugging, and aggregate counters for volume and failure rate.

I count labels as bytes and cardinality. account_ref, request IDs, and provider message IDs are useful for a trace, but they are poor permanent dimensions. A label that is unique per message creates a time series for every message in systems that index labels. Put such values in event fields or a trace context with bounded retention; reserve metric labels for dimensions such as region, template_ref, outcome, and a small retry class.

The deliberate loss is clear. After the short debugging window, an engineer may no longer be able to search every raw provider response. In exchange, the durable record can still answer the compliance question: which approved content was attempted, from which domain, and whether the application accepted the provider response. Keeping less is a control choice, not a failure to observe.

Which API comparison survives a compliance review?

A useful comparison worksheet has five columns: domain authentication, event detail, regional processing terms, retention controls, and failure semantics. SPF is one part of domain authorization, not proof that a message was delivered; RFC 7208 defines how a receiving system evaluates an SPF policy. DKIM, alignment, bounce handling, and the provider's documented processing terms need separate checks.

Run the same acceptance test against at least three public services, such as Resend, Postmark, and Mailgun, without treating their feature lists as evidence. Record whether each service documents domain verification, returns a stable message reference, exposes delivery events, states data-processing and region terms clearly, and lets the team remove or limit retained content. A fourth candidate can be useful when procurement requires a different geographic or contractual boundary. The result should be a dated test artifact, because documentation and account settings change.

Candidate Interface to test Useful fit Boundary to record
Resend REST email submission and event callbacks A small service that wants a narrow sending boundary Confirm the exact event and retention terms for the account region
Postmark REST email submission and delivery events A workflow centered on transactional message status Separate documented delivery evidence from the application audit record
Mailgun REST email submission and event data A team that needs configurable message operations Verify which processing, storage, and regional terms apply to the selected account

This table is a test plan, not a ranking. The limitation is material: none of these services is a good fit when the required processing boundary or deletion control cannot be documented. A self-hosted relay or a different contractual arrangement may then be the more appropriate boundary, even though the trade-off is more operational ownership and a larger incident-response surface.

The custom-domain test is intentionally boring. Send a verification message from the intended domain, inspect SPF and DKIM outcomes, force a rejected recipient in a non-production mailbox, and confirm that the application marks the attempt as failed without exposing the verification token in logs. Then replay the same request with an idempotency key or equivalent application guard. A retry must not create two valid account-verification paths.

Here is the shape of a generic request; the endpoint and credentials remain deployment-specific:

curl --request POST \\
  --url https://api.example.invalid/messages \\
  --header 'Authorization: Bearer ${EMAIL_API_TOKEN}' \\
  --header 'Content-Type: application/json' \\
  --data '{
    "from": "Accounts <no-reply@mail.example.eu>",
    "to": ["new-account@example.net"],
    "subject": "Verify your account",
    "template_ref": "signup-v4",
    "verification_url": "https://shop.example.eu/verify?token=REDACTED"
  }'
Enter fullscreen mode Exit fullscreen mode

The example is a protocol boundary, not a recommendation. In production, construct the verification URL in the application, redact it before request logging, and use a token with an explicit expiry. The provider response should be mapped into a small internal result type: accepted, rejected, throttled, or unknown. That mapping is more portable than copying a provider's status vocabulary throughout the signup service.

What should be sampled, and what must remain complete?

Sample routine success traces. Keep every security-relevant state transition and every failure needed to explain why an account could not be verified. A 1% sample of successful sends cannot prove that a particular account received a message; it can still reveal latency distribution and systemic regressions. This is why sampling belongs beside, not inside, the audit policy.

Use a bounded error payload: error class, retryability, provider status family, and a correlation reference. Do not log the full response by default. For a failed European signup, support may need to see the attempt time and message reference, while a compliance reviewer may need the template revision and sender domain. Neither role needs the message token.

The same rule applies to dashboards. A chart grouped by provider message ID is expensive and nearly unreadable. A chart grouped by template revision, region, outcome, and retry class answers operational questions with bounded cardinality. I would rather lose a convenient raw search after seven days than make every message a durable metric dimension.

The decision rule

Choose the API whose documented processing boundary, domain-authentication behavior, event model, and retention controls can be tested against the evidence contract. Treat advertised send volume as secondary. A lower unit price does not repair missing delivery evidence, ambiguous regional processing, or logs that retain credentials.

The final artifact should contain the test date, exact template revision, domain checks, redacted request and response samples, retention settings, and unresolved questions. It should also state what the team intentionally does not retain. That sentence is often more valuable than another feature comparison: it makes the compliance boundary explicit and gives operations a finite place to look when a verification link fails.

Further reading

Top comments (0)