diff --git a/backend/service/campaign.go b/backend/service/campaign.go index 23faab17..6410c286 100644 --- a/backend/service/campaign.go +++ b/backend/service/campaign.go @@ -3199,6 +3199,8 @@ func (c *Campaign) sendCampaignMessages( c.Logger.Errorw("failed to set envelope from", "error", err) return errs.Wrap(err) } + // message id from the sending domain so the host is not leaked + setMessageIDFromAddress(m, email.MailEnvelopeFrom.MustGet().String()) // headers err = m.From(email.MailHeaderFrom.MustGet().String()) if err != nil { @@ -5598,6 +5600,8 @@ func (c *Campaign) sendSingleEmailSMTP( c.Logger.Errorw("failed to set envelope from", "error", err) return errs.Wrap(err) } + // message id from the sending domain so the host is not leaked + setMessageIDFromAddress(m, email.MailEnvelopeFrom.MustGet().String()) // set headers err = m.From(email.MailHeaderFrom.MustGet().String()) @@ -6947,6 +6951,8 @@ func (c *Campaign) SendCampaignReport( } return errs.Wrap(err) } + // message id from the sending domain so the host is not leaked + setMessageIDFromAddress(m, senderEmail.String()) if err := m.From(senderEmail.String()); err != nil { if onDemand { return errs.NewCustomError(fmt.Errorf("the report sender email address is invalid: %w", err)) diff --git a/backend/service/email.go b/backend/service/email.go index 53f2dd03..86f6fe40 100644 --- a/backend/service/email.go +++ b/backend/service/email.go @@ -576,6 +576,8 @@ func (m *Email) SendTestEmail( m.Logger.Errorw("failed to set envelope from", "error", err) return errs.Wrap(err) } + // message id from the sending domain so the host is not leaked + setMessageIDFromAddress(msg, email.MailEnvelopeFrom.MustGet().String()) // headers err = msg.From(email.MailHeaderFrom.MustGet().String()) if err != nil { diff --git a/backend/service/messageID.go b/backend/service/messageID.go new file mode 100644 index 00000000..01830f5f --- /dev/null +++ b/backend/service/messageID.go @@ -0,0 +1,38 @@ +package service + +import ( + "strings" + + "github.com/google/uuid" + "github.com/wneessen/go-mail" +) + +// domainFromEmailAddress returns the domain part of an email address. +// it returns an empty string when the address has no domain or the domain +// does not look like a real domain (no dot). +func domainFromEmailAddress(address string) string { + at := strings.LastIndex(address, "@") + if at < 0 || at == len(address)-1 { + return "" + } + domain := strings.TrimSpace(address[at+1:]) + // a right side without a dot is not a valid domain and would look wrong + // to a receiving mail server, so treat it as unusable + if !strings.Contains(domain, ".") { + return "" + } + return domain +} + +// setMessageIDFromAddress sets the message "Message-ID" header as uuid@domain, +// using the sending domain as the right side, so outgoing mail does not carry +// the machine hostname that go-mail would otherwise use by default. +// when the address has no usable domain the message keeps whatever Message-ID +// go-mail assigns. +func setMessageIDFromAddress(m *mail.Msg, address string) { + domain := domainFromEmailAddress(address) + if domain == "" { + return + } + m.SetMessageIDWithValue(uuid.NewString() + "@" + domain) +} diff --git a/backend/service/smtpConfiguration.go b/backend/service/smtpConfiguration.go index c352c645..f35f9175 100644 --- a/backend/service/smtpConfiguration.go +++ b/backend/service/smtpConfiguration.go @@ -212,6 +212,8 @@ func (s *SMTPConfiguration) SendTestEmail( s.Logger.Errorw("failed to set envelope from", "error", err) return err } + // message id from the sending domain so the host is not leaked + setMessageIDFromAddress(m, from.String()) // headers err = m.From(from.String()) if err != nil {