You wire up SES or Postmark in an afternoon. Three lines of SDK, a verified sending domain, a DKIM record, ship it. Six months later a customer's DPO emails you: *"Please provide a current list of all subprocessors that process personal data on our behalf, including data categories and processing locations."* And you freeze — because you never pinned down whether your ESP stores the message body, for how long, in which region, and who *they* subcontract to serve the open pixel and the click-redirect.
That gap is the whole problem. Email is the most re-identifiable data you hold and the easiest to export across a processor boundary without noticing. The To/From/Cc are personal data by definition. The body is frequently special-category. And every hop — the MTA, the ESP, the tracking CDN, the archival store, an inbound-parse service, a temp-mail relay like evilmail.pro — is a separate processing surface with its own retention, its own region, and its own chain of subcontractors.
The Data Processing Agreement is where you constrain all of that. Not as a lawyer's ritual you sign once and file, but as the enforceable spec for how a vendor handles your recipients' data. Treat it the way you'd treat any other config: something you can diff, monitor and test. This is Article 28 as a runbook, written for the person who actually holds the SMTP credentials.
Why email is the hardest data-flow to paper over
Four data classes ride along with every send, and they don't share a risk profile:
- Recipient PII — the address itself is an identifier under GDPR Recital 30 and Art. 4(1). There is no "anonymous" recipient list.
- Body content — password resets are benign; a clinic's appointment reminder or a debt-collection notice is Art. 9 special-category data, which ratchets up the security-measures bar in the DPA.
- Metadata and telemetry — originating IP, User-Agent, open and click events. This is what tracking pixels and redirect domains harvest, and it's personal data too.
- Feedback-loop data — bounces, complaints, and the suppression lists built from them. "Delete this person" often means "add them to a suppression list," which is itself retained PII you now have to account for.
The roles matter because liability follows them. You, the sender, are the controller. Your ESP is a processor. The ESP's cloud infra (AWS, GCP), their sub-ESPs, their support and analytics tooling are subprocessors. Under Art. 28(4) the processor remains fully liable to you for its subprocessors' failures — but that only helps if the flow-down obligations are actually in the contract, and if you know who those subprocessors are.
The dangerous ones are invisible. A link-tracking domain, an image server for open pixels, a deliverability-analytics vendor, an inbound parsing service — each sees recipient data and each is easy to forget when someone asks you to enumerate your processors.
What Article 28 actually requires the DPA to nail down
Art. 28(3) lists eight mandatory terms. Here they are mapped to what they mean for email, not in the abstract:
- Documented instructions only — the ESP processes only on your instructions. Watch for clauses letting them use message content to train spam/ML models "to improve the service." That is processing beyond your instruction unless you agreed to it.
- Confidentiality of staff — everyone with access to the mail store is bound. Fine on paper; verify it maps to their SOC 2 access controls.
- Art. 32 security measures — encryption in transit and at rest, and if bodies can be special-category, this clause has to actually bear that weight.
- Subprocessor authorization + flow-down — general or specific authorization (28(2)), plus the obligation that subprocessors are bound by equivalent terms (28(4)).
- Assist with data-subject rights — the ESP must help you satisfy access and erasure across their store *and* their suppression lists and event logs.
- Assist with breach, DPIA and consults — feeding your Art. 33 obligation (below).
- Delete or return at end of contract — and confirm which; "delete" that leaves data in backups for 90 days is a retention fact you must record.
- Audit and inspection rights — usually satisfied by an annual SOC 2 Type II or ISO 27001 report rather than a physical audit. Make sure the report is current and on file.
The clauses people skip for email: content and log retention windows, whether IPs are scrubbed from logs, whether content is mined for models, and the sub-processing of feedback-loop data.
Then transfers. If your recipients or your establishment are in the EU/UK, exporting to a US-headquartered ESP triggers Art. 44–49. The instruments as of 2026: SCCs under Commission Implementing Decision 2021/914 (Module 2, controller-to-processor); the EU-US Data Privacy Framework, an adequacy decision in force since July 2023 — check the specific entity is certified, not just its parent; and for the UK, the IDTA or the Addendum to the SCCs. Pinning region: eu-west-1 in your SES config is necessary but not sufficient: the *data plane* stays in Ireland, but the control plane and support tooling may still be reachable from the US, which is a transfer your DPA and SCCs have to cover.
The subprocessor list as a machine-readable artifact
A subprocessor list that says AWS — hosting is a liability, not protection. A usable row carries: legal entity, role, data categories accessed, processing location(s), transfer mechanism, and a link to that subprocessor's own DPA — plus the date you last verified it.
Commit it as YAML your CI can diff:
# subprocessors.yaml — reviewed in PR, diffed on every change
- entity: "Amazon Web Services EMEA SARL"
role: "Cloud infrastructure for transactional ESP (SES)"
data_categories: [recipient_address, message_body, ip_logs, events]
location: ["IE (eu-west-1)"]
transfer_mechanism: "SCC Module 2 + EU-US DPF (control plane)"
dpa_url: "https://aws.amazon.com/service-terms/"
last_verified: "2026-06-01"Most vendors commit to a 30-day advance notice of new subprocessors with a right to object. Nobody reads those emails. Monitor the published page instead:
# Alert when a vendor's subprocessor list changes
NEW=$(curl -s https://postmarkapp.com/subprocessors | sha256sum | cut -d' ' -f1)
OLD=$(cat .subproc-hashes/postmark 2>/dev/null)
if [ "$NEW" != "$OLD" ]; then
echo "Postmark subprocessor list changed — review within objection window"
echo "$NEW" > .subproc-hashes/postmark
fiMapping your own stack to processing boundaries
Outbound: app → transactional ESP → recipient MTA, with the open-pixel CDN and click-redirect domain hanging off the side. Each side-channel is its own processor and each needs a row.
Storage: inbound → Dovecot/IMAP store or S3 archive → search index → backups. Every one of those is a place an erasure request has to reach. If you archive to S3 and index into OpenSearch, a deletion that hits only the primary store leaves two copies behind.
Temp-mail / relay (evilmail.pro): a temporary address is still personal data while it's live, and a relay is a processor. What a downstream controller needs from us is exactly what we ask of our own vendors: named retention (messages auto-purge within minutes to a few hours), no content profiling, ephemeral addresses, and no onward sale. That's the transparency you should demand — and provide.
Retention is where paper meets reality. Drop the originating IP from stored headers and cap log rotation:
# /etc/postfix/header_checks — drop stored Received headers that expose the sender IP
/^Received:.*\[.*\]/ IGNORE# /etc/logrotate.d/mail — cap MTA log retention at ~14 days
/var/log/mail.log {
daily
rotate 14
compress
missingok
}Testing the paper against reality
A DPA you've never exercised is a hypothesis. Three drills:
- Erasure drill. Issue a real Art. 17 deletion for a seeded test recipient and confirm it propagates to the ESP's stored messages, its suppression list, your analytics, and backups. Note the ESP's own retention window — Postmark keeps message content roughly 45 days by default, so "deleted now" may mean "gone in 45 days," and that's a fact you disclose, not hide.
- Retention verification. Query the ESP API for the age of stored messages,
grepyour logrotate policy, and confirm IP masking actually happened in a sampled log line. Don't trust the config; read the output. - Breach readiness. Art. 33 gives you 72 hours to notify the supervisory authority. You can't hit that if your processor takes a week to tell you. Get a 24–48h processor-to-controller notification SLA in writing, with a named security contact — not a support queue.
Practical checklist
- [ ] DPA signed and references current SCC modules (2021/914, Module 2) where transfers apply
- [ ] Subprocessor-list URL bookmarked and change alerts wired into CI
- [ ] Data categories documented per processor and subprocessor
- [ ] Region pinned for storage and acknowledged for control plane / support
- [ ] Retention numbers written down for content, logs, and telemetry
- [ ] Erasure propagation tested end-to-end, including suppression lists and backups
- [ ] Breach notification SLA (24–48h) in writing with a named security contact
- [ ] Audit right exercised: current SOC 2 Type II or ISO 27001 report on file
- [ ] DSAR runbook explicitly covers the mail store and search index
- [ ] No undisclosed content-mining / model-training clause
- [ ] Return-or-delete on termination confirmed, and which one, in writing
- [ ] Art. 30 record of processing updated with every processor and subprocessor
Wire the checklist into a review gate. A new ESP, a new tracking domain, or a subprocessor-page hash change should fail a PR until subprocessors.yaml and the Art. 30 record are updated in the same commit. The DPA and the subprocessor list are versioned config that a review gate checks — not a PDF someone dropped in a shared drive and forgot. That is the posture we hold ourselves to at evilmail.pro: short, stated retention; named processors; and no profiling of the content that passes through.


