Add support for "from_name" field in email notifications
All checks were successful
PostgreSQL Compatibility Matrix / PG14 smoke (push) Successful in 7s
PostgreSQL Compatibility Matrix / PG15 smoke (push) Successful in 7s
PostgreSQL Compatibility Matrix / PG16 smoke (push) Successful in 7s
PostgreSQL Compatibility Matrix / PG17 smoke (push) Successful in 6s
PostgreSQL Compatibility Matrix / PG18 smoke (push) Successful in 6s

Introduced a new optional "from_name" attribute to email settings, allowing customization of the sender's display name in outgoing emails. Updated backend models, APIs, and front-end components to include and handle this field properly. This enhances email clarity and personalization for users.
This commit is contained in:
2026-02-12 15:31:03 +01:00
parent ea26ef4d33
commit 648ff07651
8 changed files with 177 additions and 61 deletions

View File

@@ -0,0 +1,23 @@
"""add from_name to email settings
Revision ID: 0006_email_from_name
Revises: 0005_target_owners
Create Date: 2026-02-12
"""
from alembic import op
import sqlalchemy as sa
revision = "0006_email_from_name"
down_revision = "0005_target_owners"
branch_labels = None
depends_on = None
def upgrade() -> None:
op.add_column("email_notification_settings", sa.Column("from_name", sa.String(length=255), nullable=True))
def downgrade() -> None:
op.drop_column("email_notification_settings", "from_name")

View File

@@ -1,4 +1,5 @@
from email.message import EmailMessage
from email.utils import formataddr
import smtplib
import ssl
@@ -34,6 +35,7 @@ def _to_out(settings: EmailNotificationSettings) -> EmailSettingsOut:
smtp_host=settings.smtp_host,
smtp_port=settings.smtp_port,
smtp_username=settings.smtp_username,
from_name=settings.from_name,
from_email=settings.from_email,
use_starttls=settings.use_starttls,
use_ssl=settings.use_ssl,
@@ -64,6 +66,7 @@ async def update_email_settings(
settings.smtp_host = payload.smtp_host.strip() if payload.smtp_host else None
settings.smtp_port = payload.smtp_port
settings.smtp_username = payload.smtp_username.strip() if payload.smtp_username else None
settings.from_name = payload.from_name.strip() if payload.from_name else None
settings.from_email = str(payload.from_email) if payload.from_email else None
settings.use_starttls = payload.use_starttls
settings.use_ssl = payload.use_ssl
@@ -94,7 +97,7 @@ async def test_email_settings(
password = decrypt_secret(settings.encrypted_smtp_password) if settings.encrypted_smtp_password else None
message = EmailMessage()
message["From"] = settings.from_email
message["From"] = formataddr((settings.from_name, settings.from_email)) if settings.from_name else settings.from_email
message["To"] = str(payload.recipient)
message["Subject"] = payload.subject
message.set_content(payload.message)

View File

@@ -130,6 +130,7 @@ class EmailNotificationSettings(Base):
smtp_port: Mapped[int] = mapped_column(Integer, nullable=False, default=587)
smtp_username: Mapped[str | None] = mapped_column(String(255), nullable=True)
encrypted_smtp_password: Mapped[str | None] = mapped_column(Text, nullable=True)
from_name: Mapped[str | None] = mapped_column(String(255), nullable=True)
from_email: Mapped[str | None] = mapped_column(String(255), nullable=True)
use_starttls: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
use_ssl: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)

View File

@@ -8,6 +8,7 @@ class EmailSettingsOut(BaseModel):
smtp_host: str | None
smtp_port: int
smtp_username: str | None
from_name: str | None
from_email: EmailStr | None
use_starttls: bool
use_ssl: bool
@@ -23,6 +24,7 @@ class EmailSettingsUpdate(BaseModel):
smtp_username: str | None = None
smtp_password: str | None = None
clear_smtp_password: bool = False
from_name: str | None = None
from_email: EmailStr | None = None
use_starttls: bool = True
use_ssl: bool = False

View File

@@ -3,6 +3,7 @@ from __future__ import annotations
import asyncio
from datetime import datetime, timedelta, timezone
from email.message import EmailMessage
from email.utils import formataddr
import smtplib
import ssl
@@ -21,6 +22,7 @@ async def _smtp_send(
port: int,
username: str | None,
password: str | None,
from_name: str | None,
from_email: str,
recipient: str,
subject: str,
@@ -30,7 +32,7 @@ async def _smtp_send(
) -> None:
def _send() -> None:
message = EmailMessage()
message["From"] = from_email
message["From"] = formataddr((from_name, from_email)) if from_name else from_email
message["To"] = recipient
message["Subject"] = subject
message.set_content(body)
@@ -132,6 +134,7 @@ async def process_target_owner_notifications(db: AsyncSession, status: AlertStat
port=settings.smtp_port,
username=settings.smtp_username,
password=password,
from_name=settings.from_name,
from_email=settings.from_email,
recipient=recipient,
subject=subject,