diff --git a/pkg/coredata/email.go b/pkg/coredata/email.go index 2e8be2594..560fb7224 100644 --- a/pkg/coredata/email.go +++ b/pkg/coredata/email.go @@ -31,6 +31,7 @@ type ( ID gid.GID `db:"id"` RecipientEmail string `db:"recipient_email"` RecipientName string `db:"recipient_name"` + SenderName *string `db:"sender_name"` ReplyTo *mail.Addr `db:"reply_to"` UnsubscribeURL *string `db:"unsubscribe_url"` MailingListUpdateID *gid.GID `db:"mailing_list_update_id"` @@ -51,6 +52,7 @@ type ( Emails []*Email EmailOptions struct { + SenderName *string ReplyTo *mail.Addr UnsubscribeURL *string MailingListUpdateID *gid.GID @@ -91,6 +93,7 @@ func NewEmail( } if opts != nil { + e.SenderName = opts.SenderName e.ReplyTo = opts.ReplyTo e.UnsubscribeURL = opts.UnsubscribeURL e.MailingListUpdateID = opts.MailingListUpdateID @@ -108,7 +111,9 @@ INSERT INTO emails ( id, recipient_email, recipient_name, - reply_to, unsubscribe_url, + sender_name, + reply_to, + unsubscribe_url, mailing_list_update_id, subject, text_body, @@ -123,6 +128,7 @@ VALUES ( @id, @recipient_email, @recipient_name, + @sender_name, @reply_to, @unsubscribe_url, @mailing_list_update_id, @@ -141,6 +147,7 @@ VALUES ( "id": e.ID, "recipient_email": e.RecipientEmail, "recipient_name": e.RecipientName, + "sender_name": e.SenderName, "reply_to": e.ReplyTo, "unsubscribe_url": e.UnsubscribeURL, "mailing_list_update_id": e.MailingListUpdateID, @@ -172,6 +179,7 @@ func (emails Emails) BulkInsert( e.ID, e.RecipientEmail, e.RecipientName, + e.SenderName, e.ReplyTo, e.UnsubscribeURL, e.MailingListUpdateID, @@ -186,7 +194,7 @@ func (emails Emails) BulkInsert( _, err := conn.CopyFrom( ctx, pgx.Identifier{"emails"}, - []string{"id", "recipient_email", "recipient_name", "reply_to", "unsubscribe_url", "mailing_list_update_id", "subject", "text_body", "html_body", "created_at", "updated_at"}, + []string{"id", "recipient_email", "recipient_name", "sender_name", "reply_to", "unsubscribe_url", "mailing_list_update_id", "subject", "text_body", "html_body", "created_at", "updated_at"}, pgx.CopyFromRows(rows), ) return err @@ -198,7 +206,7 @@ func (e *Email) LoadNextPendingForUpdateSkipLocked( ) error { q := ` SELECT - id, recipient_email, recipient_name, reply_to, unsubscribe_url, mailing_list_update_id, subject, text_body, html_body, + id, recipient_email, recipient_name, sender_name, reply_to, unsubscribe_url, mailing_list_update_id, subject, text_body, html_body, status, processing_started_at, attempt_count, max_attempts, last_attempted_at, last_error, created_at, updated_at, sent_at FROM emails diff --git a/pkg/coredata/migrations/20260322T120000Z.sql b/pkg/coredata/migrations/20260322T120000Z.sql new file mode 100644 index 000000000..6cf9538f5 --- /dev/null +++ b/pkg/coredata/migrations/20260322T120000Z.sql @@ -0,0 +1 @@ +ALTER TABLE emails ADD COLUMN sender_name text; diff --git a/pkg/esign/completion_certificate_worker.go b/pkg/esign/completion_certificate_worker.go index ab6f76d5b..44322e595 100644 --- a/pkg/esign/completion_certificate_worker.go +++ b/pkg/esign/completion_certificate_worker.go @@ -238,8 +238,9 @@ func (w *CompletionCertificateWorker) generateCertificate( scope coredata.Scoper, ) (*coredata.Email, coredata.EmailAttachments, error) { var ( - events = coredata.ElectronicSignatureEvents{} - signedFile = coredata.File{} + events = coredata.ElectronicSignatureEvents{} + signedFile = coredata.File{} + organization = coredata.Organization{} ) if err := w.pg.WithConn( @@ -253,6 +254,10 @@ func (w *CompletionCertificateWorker) generateCertificate( return fmt.Errorf("cannot load signed file: %w", err) } + if err := organization.LoadByID(ctx, conn, scope, signature.OrganizationID); err != nil { + return fmt.Errorf("cannot load organization: %w", err) + } + return nil }, ); err != nil { @@ -322,7 +327,9 @@ func (w *CompletionCertificateWorker) generateCertificate( subject, textBody, htmlBody, - nil, + &coredata.EmailOptions{ + SenderName: new(organization.Name), + }, ) attachments := coredata.EmailAttachments{ diff --git a/pkg/iam/auth_service.go b/pkg/iam/auth_service.go index 1c0cf5e35..7152d2bc7 100644 --- a/pkg/iam/auth_service.go +++ b/pkg/iam/auth_service.go @@ -583,13 +583,20 @@ func (s AuthService) SendMagicLink(ctx context.Context, req *SendMagicLinkReques return fmt.Errorf("cannot render magic link email: %w", err) } + var emailOpts *coredata.EmailOptions + if req.CompliancePageID != nil { + emailOpts = &coredata.EmailOptions{ + SenderName: new(organization.Name), + } + } + magicLinkEmail := coredata.NewEmail( fullName, req.Email, subject, textBody, htmlBody, - nil, + emailOpts, ) if err := magicLinkEmail.Insert(ctx, tx); err != nil { diff --git a/pkg/mailer/mailer.go b/pkg/mailer/mailer.go index ad08a3587..53fd9b33d 100644 --- a/pkg/mailer/mailer.go +++ b/pkg/mailer/mailer.go @@ -202,9 +202,14 @@ func (w *SendingWorker) sendAndCommit( return fmt.Errorf("cannot load email attachments: %w", err) } + fromName := w.senderName + if email.SenderName != nil { + fromName = *email.SenderName + " via " + w.senderName + } + mail := enmime.Builder(). Subject(email.Subject). - From(w.senderName, w.senderEmail). + From(fromName, w.senderEmail). To(email.RecipientName, email.RecipientEmail). Text([]byte(email.TextBody)) diff --git a/pkg/mailman/service.go b/pkg/mailman/service.go index 6d358a89b..641cff934 100644 --- a/pkg/mailman/service.go +++ b/pkg/mailman/service.go @@ -708,6 +708,7 @@ func (s *Service) CreateUpdateEmails( textBody, htmlBody, &coredata.EmailOptions{ + SenderName: new(orgName), ReplyTo: replyTo, UnsubscribeURL: &unsubscribeURL, MailingListUpdateID: &mailingListUpdateID, @@ -752,7 +753,18 @@ func (s *Service) buildConfirmationMail( return nil, fmt.Errorf("cannot render subscription confirmation email: %w", err) } - return coredata.NewEmail(fullName, email, subject, textBody, htmlBody, &coredata.EmailOptions{ReplyTo: replyTo, UnsubscribeURL: &unsubscribeURL}), nil + return coredata.NewEmail( + fullName, + email, + subject, + textBody, + htmlBody, + &coredata.EmailOptions{ + SenderName: new(orgName), + ReplyTo: replyTo, + UnsubscribeURL: &unsubscribeURL, + }, + ), nil } func (s *Service) buildUnsubscriptionMail( @@ -772,7 +784,17 @@ func (s *Service) buildUnsubscriptionMail( return nil, fmt.Errorf("cannot render unsubscription email: %w", err) } - return coredata.NewEmail(fullName, email, subject, textBody, htmlBody, &coredata.EmailOptions{ReplyTo: replyTo}), nil + return coredata.NewEmail( + fullName, + email, + subject, + textBody, + htmlBody, + &coredata.EmailOptions{ + SenderName: new(orgName), + ReplyTo: replyTo, + }, + ), nil } func (s *Service) buildUnsubscribeURL(mailingListID gid.GID, email mail.Addr) (string, error) { diff --git a/pkg/probo/document_service.go b/pkg/probo/document_service.go index c6c1d663b..10df4658a 100644 --- a/pkg/probo/document_service.go +++ b/pkg/probo/document_service.go @@ -693,7 +693,9 @@ func (s *DocumentService) SendSigningNotifications( subject, textBody, htmlBody, - nil, + &coredata.EmailOptions{ + SenderName: new(organization.Name), + }, ) if err := email.Insert(ctx, tx); err != nil { diff --git a/pkg/probo/trust_center_access_service.go b/pkg/probo/trust_center_access_service.go index f779985b2..1ed7ba4c6 100644 --- a/pkg/probo/trust_center_access_service.go +++ b/pkg/probo/trust_center_access_service.go @@ -366,7 +366,9 @@ func (s TrustCenterAccessService) sendAccessEmail(ctx context.Context, tx pg.Con subject, textBody, htmlBody, - nil, + &coredata.EmailOptions{ + SenderName: new(organization.Name), + }, ) if err := accessEmail.Insert(ctx, tx); err != nil { diff --git a/pkg/trust/trust_center_access_service.go b/pkg/trust/trust_center_access_service.go index 7ed38f284..3e573f89e 100644 --- a/pkg/trust/trust_center_access_service.go +++ b/pkg/trust/trust_center_access_service.go @@ -450,7 +450,9 @@ func (s *TrustCenterAccessService) sendAccessEmail(ctx context.Context, tx pg.Co subject, textBody, htmlBody, - nil, + &coredata.EmailOptions{ + SenderName: new(organization.Name), + }, ) if err := accessEmail.Insert(ctx, tx); err != nil { @@ -585,7 +587,9 @@ func (s *TrustCenterAccessService) sendDocumentAccessRejectedEmail( subject, textBody, htmlBody, - nil, + &coredata.EmailOptions{ + SenderName: new(organization.Name), + }, ) if err := accessEmail.Insert(ctx, tx); err != nil {