A Turkish user signs up and sends one message. You now hold their email address, the connecting IP in your smtpd logs, the full Received: chain, and the message body sitting in the queue and the mailbox. Under KVKK — Law No. 6698 — all four are personal data, and you are the *veri sorumlusu* (data controller) for the ones tied to your own signup. This is not abstract exposure. It is a 72-hour notification clock the moment something leaks, and administrative fines that get re-indexed upward every January. The theory is settled; what matters is what has to be true inside your stack. Three things: a logged Turkish-language consent record, a retention-and-destruction policy that actually runs on mail.log, and a breach runbook that can hit the Board's clock without improvising.
What counts as personal data in a mail stack
KVKK Art. 3 defines *kişisel veri* as any information relating to an identified or identifiable natural person. Map that onto your artifacts and almost the whole pipeline lights up:
- The email address in
MAIL FROM/RCPT TO— personal data, full stop. - The source IP in
postfix/smtpd[...]: connect from mail.example.com[203.0.113.7]and every hop of theReceived:header chain. The Kurul has consistently treated IP addresses as personal data because they become identifiable when combined with subscriber records. - Dovecot's
imap-login: Login: user=<[email protected]>, rip=203.0.113.7— address plus IP in one line. - The message body and attachments, which you cannot pre-filter and which may contain *özel nitelikli kişisel veri* (special-category data): health data, ID numbers, biometric or religious information a sender drops into an email you now store.
Two roles matter. If you run SMTP/IMAP for a customer's own domain, you are usually their *veri işleyen* (processor) — you act on their instructions. For your own signup, session, and billing data you are the *veri sorumlusu* (controller). Most platforms are both at once, and the obligations differ. And do not reach for the "we're anonymous / temp-mail" exemption: pseudonymous data is still personal data. A disposable inbox that never asks for a name still logs a source IP and routes to a real recipient, so KVKK still applies.
Consent, açık rıza, and the aydınlatma metni
People conflate two obligations that KVKK deliberately keeps separate. The Art. 10 *aydınlatma yükümlülüğü* (duty to inform) is always required, independent of consent — every data subject must be told who the controller is, what you collect, why, on what legal basis, and what their rights are. The Art. 5 *açık rıza* (explicit consent) is only one of several lawful grounds, and you reach for it only when no other ground applies.
For a mail service this distinction saves real work. Running the mailbox is *sözleşmenin ifası* — performance of a contract. You do not need consent to accept, store, and deliver mail for someone who asked you to; that is the service. You do need explicit consent for anything outside the core contract: marketing email, non-essential analytics cookies, and — critically — cross-border transfer. Explicit consent must be freely given, specific, informed, and separable. A checkbox bundled into your Terms of Service is invalid; consent glued to acceptance of the ToS is not "freely given."
The engineering job is proving all of this years later. Version the notice, hash it, and record the consent event with enough context to reconstruct exactly what the subject saw:
CREATE TABLE consent_record (
id BIGSERIAL PRIMARY KEY,
subject_email TEXT NOT NULL,
purpose TEXT NOT NULL, -- 'marketing' | 'cross_border' | 'analytics'
notice_version TEXT NOT NULL, -- hash of the aydınlatma metni shown
consented BOOLEAN NOT NULL,
ip INET, -- collection-time IP
user_agent TEXT,
locale TEXT NOT NULL DEFAULT 'tr',
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);When the Kurul asks how you obtained consent, you produce a row: the purpose, the exact notice version, the checkbox state, and when. One row per purpose — never a single "I agree to everything" flag.
Localization is a compliance control, not a UX nicety
Two artifacts must be in Turkish for a Turkish *ilgili kişi*: the aydınlatma metni and the consent UI. A notice a subject cannot read is not "informed" consent — it is decorative. On a platform that already ships 12 locales this is cheap; the point is that Turkish here is a legal requirement, not a translation backlog item.
The harder half is cross-border transfer. Law No. 7499 (published 12 March 2024, in force 1 June 2024) rewrote Art. 9 into a GDPR-shaped regime with a strict order of preference:
- 1.Yeterlilik kararı — an adequacy decision for the destination country. None have been issued yet, so in practice this rarely helps.
- 2.Appropriate safeguards — the Kurul's published *standart sözleşme* (standard contract), *bağlayıcı şirket kuralları* (binding corporate rules), or an international agreement. The standard contract must be notified to the Authority within 5 business days of signing.
- 3.Narrow derogations under Art. 9/6 — explicit consent, contract necessity, and a handful of others, read narrowly.
The trigger for a mail operator is concrete and easy to hit by accident: the moment your mailboxes, MX, or backups sit on infrastructure outside Türkiye, you are doing a *yurt dışı aktarım*. An offshore VPS, a non-TR backup bucket, a third-party spam/AV scanning API, or piping outbound through a US email API — each is a cross-border transfer that needs a lawful mechanism. Check your VERBİS registration thresholds too; controllers above them must be registered before they process.
Retention and destruction: the policy that lives in logrotate
The 2017 Regulation on Deletion, Destruction or Anonymization of Personal Data requires a written *Kişisel Veri Saklama ve İmha Politikası* and actual enforcement, with *periyodik imha* (periodic destruction) at intervals not exceeding 6 months. "We keep logs forever" is a finding waiting to happen. Translate the policy into ops.
First, define retention windows per data class:
| Data class | Window | Basis |
|---|---|---|
| Auth / login logs | 30 gün | Art. 12 security + abuse defense |
SMTP mail.log | 30 gün, IP anonymized after 7 gün | meşru menfaat |
| Temp-email mailbox | 1h / 24h TTL auto-purge | veri minimizasyonu |
| Delivered customer mail | contract term + 30 gün | sözleşme |
| Backups | 90 gün rolling, encrypted at rest | security |
| Periyodik imha job | every ≤ 6 ay | 2017 Regulation |
Then enforce it. Rotation and capped retention on the mail logs:
# /etc/logrotate.d/mail
/var/log/mail.log /var/log/mail.info {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 0640 syslog adm
postrotate
/usr/lib/rsyslog/rsyslog-rotate >/dev/null 2>&1 || true
endscript
}And anonymize the IPs you no longer need for a fail2ban or abuse window — mask the last octet in rotated logs so you keep operational usefulness without keeping identifiable data:
# /etc/cron.d/mail-anon — mask last IPv4 octet in rotated log, then compress
0 3 * * * root sed -ri 's/(([0-9]{1,3}\.){3})[0-9]{1,3}/\10/g' /var/log/mail.log.1 && gzip -f /var/log/mail.log.1IPv6 needs a second pattern, and you should only anonymize logs outside your active abuse-defense window — raw IPs for the last few days still feed fail2ban. This is where temp-email quietly wins: a mailbox with a 1-hour TTL is *veri minimizasyonu* done natively. The strongest compliance posture is data you already destroyed, and a disposable inbox destroys it by design.
Breach notification: beating the 72-hour clock
Art. 12 makes you responsible for data security. Board decision of 24 January 2019, No. 2019/10, puts a hard number on the aftermath: notify the Kurul within 72 hours of becoming aware of a breach, and notify affected data subjects *makul olan en kısa süre içinde* — as soon as reasonably possible. The filing channel is the online *İhlal Bildirim Formu* on the Authority's site.
The trap is the word "aware." The clock runs from awareness, not from the end of your investigation. "We're still scoping it" pauses nothing. That is why this has to be a runbook with an owner, not a scramble.
The runbook, step by step. Detect: fail2ban firing on abnormal IMAP auth, an exposed database dump, an unexpected outbound spam spike. Scope: which data classes (addresses, IPs, bodies) and roughly how many *ilgili kişi* are affected. File: the İhlal Bildirim Formu wants the nature of the breach, the categories and approximate number of affected subjects and records, the likely consequences, and the measures taken. Notify the affected subjects. Log every timestamp and decision — your own record is what proves you met the clock. Name a single owner in advance so nobody burns the first six of your seventy-two hours deciding who files.
What actually triggers a fine
Art. 18 administrative fines are re-indexed every January by the *yeniden değerleme oranı* (the 2024 rate was 43.93%), so any figure you memorize is stale within a year — treat them as 2025 bands that climb annually. The mapping matters more than the numbers:
- No or inadequate aydınlatma metni — the lower band, indicatively tens of thousands up to roughly 1M TL.
- Art. 12 data-security failures — the breach cases, the high band, up into the ~9.4M TL range (2025 figures).
- VERBİS non-registration — penalized separately, on its own track.
The Kurul publishes anonymized *Karar Özetleri* (decision summaries). Read them. They are a free, continuously updated threat model showing exactly which failures got fined and how the Board reasoned — cheaper than any consultant.
Compliance checklist
- Turkish-language aydınlatma metni live and versioned at every collection point.
- Consent separated from ToS, one row per purpose, logged with notice version + IP + locale.
- VERBİS registration status decided against current thresholds.
- Cross-border mechanism in place if any infra is offshore — standart sözleşme filed within 5 iş günü of signing.
- Retention windows codified in logrotate and per data class, not left to "forever."
- IP anonymization job running on rotated logs outside the abuse-defense window.
- Periyodik imha scheduled at intervals ≤ 6 ay.
- Breach runbook written, with a named 72-hour owner.
- İhlal Bildirim Formu draft pre-filled with your controller details so filing is minutes, not hours.


