Prompt
I'm building a regulated product and need audit logs for email sends
Latest observation
Oct 4, 2026
OpenAI APIWeb search: off
For a regulated product, your email-send audit trail should be designed so you can answer:
- What was sent?
- To whom?
- When?
- By whom / what system?
- Why was it sent?
- What happened to it afterward?
- Can we prove the record wasn’t altered?
A good pattern is to log email events as an immutable audit stream, not just a single “sent” record.
What to log
Core fields
- event_id: unique ID for this audit event
- message_id / provider_message_id: internal and provider-side IDs
- timestamp: precise UTC timestamp
- event_type: queued, accepted, sent, delivered, bounced, opened, clicked, failed, suppressed, etc.
- status: success/failure/pending
- recipient: email address; consider hashing/tokenizing if needed
- sender: from address / display name
- subject: if allowed by policy
- template_id and template_version
- campaign_id / notification_id / workflow_id
- actor: user/service account/system job that triggered send
- tenant/customer/account_id
- correlation_id / trace_id
- provider: SES, SendGrid, etc.
- provider_response: message only, no secrets
- error_code / error_message for failures
- policy_context: consent basis, legal basis, notification category
- content_hash: hash of rendered email body/attachments for integrity
Compliance-friendly additions
- consent_snapshot_id or reference to consent record
- suppression_reason if blocked
- retention_classification
- data_classification of the email
- pii_redaction_flag
- jurisdiction / region
- delivery_metadata: SMTP response, webhook event type
Recommended architecture
1) Immutable append-only audit log
Write each event as a new row/document only. Never update in place. If something changes, write a new event.
2) Separate operational data from audit data
- Operational table: current notification state
- Audit store: immutable event history
3) Include hashes for integrity
- Hash the rendered message and metadata
- Optionally chain audit records with a previous-record hash to detect tampering
4) Restrict access
- Tight RBAC
- Read-only access for auditors
- Separate encryption keys for audit data
- Full admin actions should themselves be audited
5) Retention and deletion policy
Regulated systems often need:
- Defined retention periods
- Legal hold support
- PII minimization
- Deletion/anonymization workflows that preserve auditability where required
Example audit event schema
{
"event_id": "evt_01J2...",
"event_type": "email.sent",
"timestamp": "2026-10-04T12:34:56.789Z",
"tenant_id": "tenant_123",
"actor_type": "service",
"actor_id": "notification-worker",
"recipient": "user@example.com",
"sender": "noreply@company.com",
"subject": "Your statement is ready",
"template_id": "stmt_ready",
"template_version": "v14",
"notification_id": "notif_456",
"provider": "ses",
"provider_message_id": "0100018b...",
"status": "success",
"correlation_id": "trace_789",
"content_hash": "sha256:ab12...",
"consent_snapshot_id": "consent_321",
"policy_context": {
"category": "transactional",
"legal_basis": "contract"
},
"metadata": {
"smtp_response": "250 2.0.0 OK",
"ip": "redacted"
}
}
Important pitfalls to avoid
- Storing full email bodies in plain logs
- Logging secrets, tokens, or attachments without controls
- Using mutable logs that can be edited
- Lack of time synchronization
- No record of failed or suppressed sends
- No linkage to consent or authorization context
Minimum viable audit trail
If you want the smallest compliant baseline:
- recipient
- sender
- timestamp
- event type/status
- actor/system
- template/version or content hash
- message/provider ID
- correlation ID
- consent/policy reference
- immutable storage
If you want, I can also provide:
- a PostgreSQL schema
- an event model for Kafka/SNS/SQS
- a Python/Node logging example
- a retention and tamper-evidence design
- a SOC 2 / HIPAA / GDPR-oriented checklist