Skip to content

Commit cff55d4

Browse files
spashiiclaude
andcommitted
feat(email): route SendGrid sends through EU data residency
Add SENDGRID_REGION (default "eu") and call set_sendgrid_data_residency() so the app's transactional email (email.py -> SendGrid HTTP API) routes through api.eu.sendgrid.com, keeping recipient PII and content in EU data centers. Requires SENDGRID_API_KEY to belong to an EU regional subuser. Note: the echo-directus container sends its own emails via SMTP and must separately move to smtp.eu.sendgrid.net with the EU subuser key (infra). Refs ECHO-832 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 8cd1e63 commit cff55d4

3 files changed

Lines changed: 20 additions & 0 deletions

File tree

echo/server/.env.sample

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,12 @@ EMBEDDING_API_VERSION=
9191
# Email (SendGrid)
9292
############################################################
9393
# API key for SendGrid transactional emails. Leave empty to disable sends.
94+
# For EU data residency this must be an EU regional subuser key.
9495
SENDGRID_API_KEY=
96+
# Data residency region: "eu" (default, routes via api.eu.sendgrid.com) or
97+
# "global". "eu" keeps recipient PII and content in EU data centers and
98+
# requires the key above to belong to an EU regional subuser.
99+
SENDGRID_REGION=eu
95100
EMAIL_FROM=do-not-reply@dembrane.com
96101
EMAIL_FROM_NAME=dembrane
97102
# Where "Request upgrade" CTAs route. Shared inbox per matrix v1.1 §11.

echo/server/dembrane/email.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,12 @@ def send_email_sync(
177177
)
178178

179179
sg = SendGridAPIClient(api_key)
180+
# Pin the send to a data-residency region. "eu" routes through
181+
# api.eu.sendgrid.com so recipient PII and content stay in the EU.
182+
# The key must belong to a subuser in this region.
183+
region = settings.email.sendgrid_region
184+
if region and region != "global":
185+
sg.set_sendgrid_data_residency(region)
180186
response = sg.send(message)
181187

182188
if response.status_code >= 400:

echo/server/dembrane/settings.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,15 @@ class EmailSettings(BaseSettings):
323323
"SENDGRID_API_KEY", "EMAIL__SENDGRID_API_KEY", "EMAIL_SMTP_PASSWORD"
324324
),
325325
)
326+
# SendGrid data residency region. "eu" routes sends through
327+
# api.eu.sendgrid.com so recipient PII and content stay in EU data
328+
# centers (GDPR). Requires an EU regional subuser key. "global" uses
329+
# api.sendgrid.com. The key must belong to a subuser in this region.
330+
sendgrid_region: str = Field(
331+
default="eu",
332+
alias="SENDGRID_REGION",
333+
validation_alias=AliasChoices("SENDGRID_REGION", "EMAIL__SENDGRID_REGION"),
334+
)
326335
from_email: str = Field(
327336
default="do-not-reply@dembrane.com",
328337
alias="EMAIL_FROM",

0 commit comments

Comments
 (0)