feat: add BCC support to email service — admin copy of every email
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions

Every email sent via send_email() now includes a BCC to the portal
administrator (MAIL_BCC env var, defaults to maciej.pienczyn@inpi.pl).
Recipients who are already in TO are automatically excluded from BCC.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Maciej Pienczyn 2026-02-21 17:36:02 +01:00
parent 5d764b06c3
commit e2ae68eeed

View File

@ -90,7 +90,8 @@ class EmailService:
subject: str,
body_text: str,
body_html: Optional[str] = None,
from_address: Optional[str] = None
from_address: Optional[str] = None,
bcc: Optional[List[str]] = None
) -> bool:
"""
Send email via Microsoft Graph API
@ -101,6 +102,7 @@ class EmailService:
body_text: Plain text email body
body_html: HTML email body (optional)
from_address: Sender email (optional, defaults to configured mail_from)
bcc: List of BCC recipient email addresses (optional)
Returns:
True if sent successfully, False otherwise
@ -152,6 +154,11 @@ class EmailService:
"saveToSentItems": "false"
}
# Add BCC recipients if provided
if bcc:
bcc_recipients = [{"emailAddress": {"address": email}} for email in bcc]
email_msg["message"]["bccRecipients"] = bcc_recipients
# Send email via Graph API
url = f"{self.graph_endpoint}/users/{sender}/sendMail"
headers = {
@ -211,7 +218,8 @@ def send_email(
from_address: Optional[str] = None,
email_type: str = 'notification',
user_id: Optional[int] = None,
recipient_name: Optional[str] = None
recipient_name: Optional[str] = None,
bcc: Optional[List[str]] = None
) -> bool:
"""
Send email using the global Email Service instance
@ -225,6 +233,7 @@ def send_email(
email_type: Type of email for logging (welcome, password_reset, notification)
user_id: User ID for logging (optional)
recipient_name: Recipient name for logging (optional)
bcc: List of BCC emails (optional, defaults to MAIL_BCC env var)
Returns:
True if sent successfully, False otherwise
@ -237,7 +246,15 @@ def send_email(
if isinstance(to, str):
to = [to]
result = _email_service.send_mail(to, subject, body_text, body_html, from_address)
# Default BCC from env var — admin gets a copy of every email
if bcc is None:
default_bcc = os.getenv('MAIL_BCC', 'maciej.pienczyn@inpi.pl')
if default_bcc:
bcc = [addr.strip() for addr in default_bcc.split(',') if addr.strip()]
# Don't BCC someone who is already a direct recipient
bcc = [addr for addr in bcc if addr not in to]
result = _email_service.send_mail(to, subject, body_text, body_html, from_address, bcc=bcc)
# Log email to database
_log_email(