mirror of
https://github.com/axllent/mailpit.git
synced 2025-05-15 22:16:44 +02:00
140 lines
3.7 KiB
Go
140 lines
3.7 KiB
Go
package smtpd
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"fmt"
|
|
"net/smtp"
|
|
"strings"
|
|
|
|
"github.com/axllent/mailpit/config"
|
|
"github.com/axllent/mailpit/internal/logger"
|
|
"github.com/axllent/mailpit/internal/tools"
|
|
)
|
|
|
|
// Wrapper to forward messages if configured
|
|
func autoForwardMessage(from string, data *[]byte) {
|
|
if config.SMTPForwardConfig.Host == "" {
|
|
return
|
|
}
|
|
|
|
if err := forward(from, *data); err != nil {
|
|
logger.Log().Errorf("[forward] error: %s", err.Error())
|
|
} else {
|
|
logger.Log().Debugf("[forward] message from %s to %s via %s:%d",
|
|
from, config.SMTPForwardConfig.To, config.SMTPForwardConfig.Host, config.SMTPForwardConfig.Port)
|
|
}
|
|
}
|
|
|
|
func createForwardingSMTPClient(config config.SMTPForwardConfigStruct, addr string) (*smtp.Client, error) {
|
|
if config.TLS {
|
|
tlsConf := &tls.Config{ServerName: config.Host} // #nosec
|
|
tlsConf.InsecureSkipVerify = config.AllowInsecure
|
|
|
|
conn, err := tls.Dial("tcp", addr, tlsConf)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("TLS dial error: %v", err)
|
|
}
|
|
|
|
client, err := smtp.NewClient(conn, tlsConf.ServerName)
|
|
if err != nil {
|
|
conn.Close()
|
|
return nil, fmt.Errorf("SMTP client error: %v", err)
|
|
}
|
|
|
|
// Note: The caller is responsible for closing the client
|
|
return client, nil
|
|
}
|
|
|
|
client, err := smtp.Dial(addr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error connecting to %s: %v", addr, err)
|
|
}
|
|
|
|
if config.STARTTLS {
|
|
tlsConf := &tls.Config{ServerName: config.Host} // #nosec
|
|
tlsConf.InsecureSkipVerify = config.AllowInsecure
|
|
|
|
if err = client.StartTLS(tlsConf); err != nil {
|
|
client.Close()
|
|
return nil, fmt.Errorf("error creating StartTLS config: %v", err)
|
|
}
|
|
}
|
|
|
|
// Note: The caller is responsible for closing the client
|
|
return client, nil
|
|
}
|
|
|
|
// Forward will connect to a pre-configured SMTP server and send a message to one or more recipients.
|
|
func forward(from string, msg []byte) error {
|
|
addr := fmt.Sprintf("%s:%d", config.SMTPForwardConfig.Host, config.SMTPForwardConfig.Port)
|
|
|
|
c, err := createForwardingSMTPClient(config.SMTPForwardConfig, addr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer c.Close()
|
|
|
|
auth := forwardAuthFromConfig()
|
|
|
|
if auth != nil {
|
|
if err = c.Auth(auth); err != nil {
|
|
return fmt.Errorf("error response to AUTH command: %s", err.Error())
|
|
}
|
|
}
|
|
|
|
if config.SMTPForwardConfig.OverrideFrom != "" {
|
|
msg, err = tools.OverrideFromHeader(msg, config.SMTPForwardConfig.OverrideFrom)
|
|
if err != nil {
|
|
return fmt.Errorf("error overriding From header: %s", err.Error())
|
|
}
|
|
|
|
from = config.SMTPForwardConfig.OverrideFrom
|
|
}
|
|
|
|
if err = c.Mail(from); err != nil {
|
|
return fmt.Errorf("error response to MAIL command: %s", err.Error())
|
|
}
|
|
|
|
to := strings.Split(config.SMTPForwardConfig.To, ",")
|
|
|
|
for _, addr := range to {
|
|
if err = c.Rcpt(addr); err != nil {
|
|
logger.Log().Warnf("error response to RCPT command for %s: %s", addr, err.Error())
|
|
}
|
|
}
|
|
|
|
w, err := c.Data()
|
|
if err != nil {
|
|
return fmt.Errorf("error response to DATA command: %s", err.Error())
|
|
}
|
|
|
|
if _, err := w.Write(msg); err != nil {
|
|
return fmt.Errorf("error sending message: %s", err.Error())
|
|
}
|
|
|
|
if err := w.Close(); err != nil {
|
|
return fmt.Errorf("error closing connection: %s", err.Error())
|
|
}
|
|
|
|
return c.Quit()
|
|
}
|
|
|
|
// Return the SMTP forwarding authentication based on config
|
|
func forwardAuthFromConfig() smtp.Auth {
|
|
var a smtp.Auth
|
|
|
|
if config.SMTPForwardConfig.Auth == "plain" {
|
|
a = smtp.PlainAuth("", config.SMTPForwardConfig.Username, config.SMTPForwardConfig.Password, config.SMTPForwardConfig.Host)
|
|
}
|
|
|
|
if config.SMTPForwardConfig.Auth == "login" {
|
|
a = LoginAuth(config.SMTPForwardConfig.Username, config.SMTPForwardConfig.Password)
|
|
}
|
|
|
|
if config.SMTPForwardConfig.Auth == "cram-md5" {
|
|
a = smtp.CRAMMD5Auth(config.SMTPForwardConfig.Username, config.SMTPForwardConfig.Secret)
|
|
}
|
|
|
|
return a
|
|
}
|