mirror of
https://github.com/go-gitea/gitea.git
synced 2025-12-06 18:20:47 +01:00
Backport #36055 by @lunny Replace #36032 Fix #36030 This PR use `net/smtp` instead of gomail's smtp. Now github.com/wneessen/go-mail will be used only for generating email message body. Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
parent
52902d4ece
commit
0ab447005d
@ -33,7 +33,13 @@ func (s *SendmailSender) Send(from string, to []string, msg io.WriterTo) error {
|
||||
|
||||
args := []string{"-f", envelopeFrom, "-i"}
|
||||
args = append(args, setting.MailService.SendmailArgs...)
|
||||
args = append(args, to...)
|
||||
for _, recipient := range to {
|
||||
smtpTo, err := sanitizeEmailAddress(recipient)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid recipient address %q: %w", recipient, err)
|
||||
}
|
||||
args = append(args, smtpTo)
|
||||
}
|
||||
log.Trace("Sending with: %s %v", setting.MailService.SendmailPath, args)
|
||||
|
||||
desc := fmt.Sprintf("SendMail: %s %v", setting.MailService.SendmailPath, args)
|
||||
|
||||
@ -9,13 +9,13 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/mail"
|
||||
"net/smtp"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/wneessen/go-mail/smtp"
|
||||
)
|
||||
|
||||
// SMTPSender Sender SMTP mail sender
|
||||
@ -108,7 +108,7 @@ func (s *SMTPSender) Send(from string, to []string, msg io.WriterTo) error {
|
||||
if strings.Contains(options, "CRAM-MD5") {
|
||||
auth = smtp.CRAMMD5Auth(opts.User, opts.Passwd)
|
||||
} else if strings.Contains(options, "PLAIN") {
|
||||
auth = smtp.PlainAuth("", opts.User, opts.Passwd, host, false)
|
||||
auth = smtp.PlainAuth("", opts.User, opts.Passwd, host)
|
||||
} else if strings.Contains(options, "LOGIN") {
|
||||
// Patch for AUTH LOGIN
|
||||
auth = LoginAuth(opts.User, opts.Passwd)
|
||||
@ -123,18 +123,24 @@ func (s *SMTPSender) Send(from string, to []string, msg io.WriterTo) error {
|
||||
}
|
||||
}
|
||||
|
||||
if opts.OverrideEnvelopeFrom {
|
||||
if err = client.Mail(opts.EnvelopeFrom); err != nil {
|
||||
return fmt.Errorf("failed to issue MAIL command: %w", err)
|
||||
}
|
||||
} else {
|
||||
if err = client.Mail(fmt.Sprintf("<%s>", from)); err != nil {
|
||||
return fmt.Errorf("failed to issue MAIL command: %w", err)
|
||||
}
|
||||
fromAddr := from
|
||||
if opts.OverrideEnvelopeFrom && opts.EnvelopeFrom != "" {
|
||||
fromAddr = opts.EnvelopeFrom
|
||||
}
|
||||
smtpFrom, err := sanitizeEmailAddress(fromAddr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid envelope from address: %w", err)
|
||||
}
|
||||
if err = client.Mail(smtpFrom); err != nil {
|
||||
return fmt.Errorf("failed to issue MAIL command: %w", err)
|
||||
}
|
||||
|
||||
for _, rec := range to {
|
||||
if err = client.Rcpt(rec); err != nil {
|
||||
smtpTo, err := sanitizeEmailAddress(rec)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid recipient address %q: %w", rec, err)
|
||||
}
|
||||
if err = client.Rcpt(smtpTo); err != nil {
|
||||
return fmt.Errorf("failed to issue RCPT command: %w", err)
|
||||
}
|
||||
}
|
||||
@ -155,3 +161,11 @@ func (s *SMTPSender) Send(from string, to []string, msg io.WriterTo) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func sanitizeEmailAddress(raw string) (string, error) {
|
||||
addr, err := mail.ParseAddress(strings.TrimSpace(strings.Trim(raw, "<>")))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return addr.Address, nil
|
||||
}
|
||||
|
||||
@ -6,9 +6,9 @@ package sender
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/smtp"
|
||||
|
||||
"github.com/Azure/go-ntlmssp"
|
||||
"github.com/wneessen/go-mail/smtp"
|
||||
)
|
||||
|
||||
type loginAuth struct {
|
||||
|
||||
30
services/mailer/sender/smtp_test.go
Normal file
30
services/mailer/sender/smtp_test.go
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package sender
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestSanitizeEmailAddress(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
expected string
|
||||
hasError bool
|
||||
}{
|
||||
{"abc@gitea.com", "abc@gitea.com", false},
|
||||
{"<abc@gitea.com>", "abc@gitea.com", false},
|
||||
{"ssss.com", "", true},
|
||||
{"<invalid-email>", "", true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
result, err := sanitizeEmailAddress(tt.input)
|
||||
if (err != nil) != tt.hasError {
|
||||
t.Errorf("sanitizeEmailAddress(%q) unexpected error status: got %v, want error: %v", tt.input, err != nil, tt.hasError)
|
||||
continue
|
||||
}
|
||||
if result != tt.expected {
|
||||
t.Errorf("sanitizeEmailAddress(%q) = %q; want %q", tt.input, result, tt.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user