Просмотр исходного кода

Merge pull request #74 from Jinnrry/v2.3.7

v2.3.7 (#3)
木木的木头 2 лет назад
Родитель
Сommit
2467061431

+ 2 - 2
README.md

@@ -61,10 +61,10 @@ First go to [spamhaus](https://check.spamhaus.org/) and check your domain name a
 
 Or 
 
-`docker run -p 25:25 -p 80:80 -p 443:443 -p 110:110 -p 465:465 -v $(pwd)/config:/work/config ghcr.io/jinnrry/pmail:latest`
+`docker run -p 25:25 -p 80:80 -p 443:443 -p 110:110 -p 465:465 -p 995:995 -v $(pwd)/config:/work/config ghcr.io/jinnrry/pmail:latest`
 
 > [!IMPORTANT]
-> If your server has a firewall turned on, you need to open ports 25, 80, 110, 443, 465
+> If your server has a firewall turned on, you need to open ports 25, 80, 110, 443, 465, 995
 
 ## 3、Configuration
 

+ 2 - 2
README_CN.md

@@ -65,10 +65,10 @@ PMail是一个追求极简部署流程、极致资源占用的个人域名邮箱
 
 或者
 
-`docker run -p 25:25 -p 80:80 -p 443:443 -p 110:110 -p 465:465 -v $(pwd)/config:/work/config ghcr.io/jinnrry/pmail:latest`
+`docker run -p 25:25 -p 80:80 -p 443:443 -p 110:110 -p 465:465 -p 995:995 -v $(pwd)/config:/work/config ghcr.io/jinnrry/pmail:latest`
 
 > [!IMPORTANT]
-> 如果你服务器开启了防火墙,你需要放行25、80、110、443、465这五个端口
+> 如果你服务器开启了防火墙,你需要打开25、80、110、443、465、995端口
 
 ## 3、配置
 

+ 1 - 1
server/config/config.go

@@ -39,7 +39,7 @@ type Config struct {
 //go:embed tables/*
 var tableConfig embed.FS
 
-const Version = "2.3.6"
+const Version = "2.3.7"
 
 const DBTypeMySQL = "mysql"
 const DBTypeSQLite = "sqlite"

+ 2 - 2
server/go.mod

@@ -5,7 +5,7 @@ go 1.21
 require (
 	github.com/Jinnrry/gopop v0.0.0-20231113115125-fbdf52ae39ea
 	github.com/alexedwards/scs/mysqlstore v0.0.0-20230327161757-10d4299e3b24
-	github.com/alexedwards/scs/sqlite3store v0.0.0-20230327161757-10d4299e3b24
+	github.com/alexedwards/scs/sqlite3store v0.0.0-20231113091146-cef4b05350c8
 	github.com/alexedwards/scs/v2 v2.5.1
 	github.com/emersion/go-message v0.18.0
 	github.com/emersion/go-msgauth v0.6.6
@@ -21,7 +21,7 @@ require (
 	modernc.org/sqlite v1.24.0
 )
 
-replace github.com/alexedwards/scs/sqlite3store v0.0.0-20230327161757-10d4299e3b24 => github.com/Jinnrry/scs/sqlite3store v0.0.0-20230803080525-914f01e0d379
+replace github.com/emersion/go-smtp v0.20.1 => github.com/jinnrry/go-smtp v0.20.1
 
 require (
 	github.com/cenkalti/backoff/v4 v4.2.1 // indirect

+ 5 - 2
server/go.sum

@@ -4,6 +4,9 @@ github.com/Jinnrry/scs/sqlite3store v0.0.0-20230803080525-914f01e0d379 h1:i6LB/3
 github.com/Jinnrry/scs/sqlite3store v0.0.0-20230803080525-914f01e0d379/go.mod h1:Iyk7S76cxGaiEX/mSYmTZzYehp4KfyylcLaV3OnToss=
 github.com/alexedwards/scs/mysqlstore v0.0.0-20230327161757-10d4299e3b24 h1:1jXpX7IE/zuf9FZQJpqZNepXqW8mq6NLzplHDCA43HY=
 github.com/alexedwards/scs/mysqlstore v0.0.0-20230327161757-10d4299e3b24/go.mod h1:ShejCOaSJCEjCWjc7YBrgy2xd0Kp+wiyBdzTNQrAGn4=
+github.com/alexedwards/scs/sqlite3store v0.0.0-20230327161757-10d4299e3b24/go.mod h1:Iyk7S76cxGaiEX/mSYmTZzYehp4KfyylcLaV3OnToss=
+github.com/alexedwards/scs/sqlite3store v0.0.0-20231113091146-cef4b05350c8 h1:mnXnnXEjn8QIyv4KCN0+IjDlXA64qdq2hIVOmfNFeuY=
+github.com/alexedwards/scs/sqlite3store v0.0.0-20231113091146-cef4b05350c8/go.mod h1:Iyk7S76cxGaiEX/mSYmTZzYehp4KfyylcLaV3OnToss=
 github.com/alexedwards/scs/v2 v2.5.1 h1:EhAz3Kb3OSQzD8T+Ub23fKsiuvE0GzbF5Lgn0uTwM3Y=
 github.com/alexedwards/scs/v2 v2.5.1/go.mod h1:ToaROZxyKukJKT/xLcVQAChi5k6+Pn1Gvmdl7h3RRj8=
 github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
@@ -22,8 +25,6 @@ github.com/emersion/go-msgauth v0.6.6 h1:buv5lL8v/3v4RpHnQFS2IPhE3nxSRX+AxnrEJbD
 github.com/emersion/go-msgauth v0.6.6/go.mod h1:A+/zaz9bzukLM6tRWRgJ3BdrBi+TFKTvQ3fGMFOI9SM=
 github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 h1:OJyUGMJTzHTd1XQp98QTaHernxMYzRaOasRir9hUlFQ=
 github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
-github.com/emersion/go-smtp v0.20.1 h1:kW8Nkzomjk6W1ebfUYy6wAYThukCzD9MFOkFnragOHc=
-github.com/emersion/go-smtp v0.20.1/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
 github.com/emersion/go-textwrapper v0.0.0-20160606182133-d0e65e56babe/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
 github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594 h1:IbFBtwoTQyw0fIM5xv1HF+Y+3ZijDR839WMulgxCcUY=
 github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
@@ -44,6 +45,8 @@ github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbu
 github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
 github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
 github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/jinnrry/go-smtp v0.20.1 h1:coy2+Ch7+ptr3J4rHwE+YVY25eaXuUbi4PNHchfc6ro=
+github.com/jinnrry/go-smtp v0.20.1/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
 github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
 github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=

+ 1 - 1
server/smtp_server/smtp.go

@@ -110,7 +110,7 @@ func StartWithTLS() {
 	instanceTls.MaxMessageBytes = 1024 * 1024
 	instanceTls.MaxRecipients = 50
 	// force TLS for auth
-	instanceTls.AllowInsecureAuth = false
+	instanceTls.AllowInsecureAuth = true
 	// Load the certificate and key
 	cer, err := tls.LoadX509KeyPair(config.Instance.SSLPublicKeyPath, config.Instance.SSLPrivateKeyPath)
 	if err != nil {

+ 15 - 12
server/utils/send/send.go

@@ -154,25 +154,24 @@ func Send(ctx *context.Context, e *parsemail.Email) (error, map[string]error) {
 		as.WaitProcess(func(p any) {
 
 			err := smtp.SendMail("", domain.mxHost+":25", nil, e.From.EmailAddress, buildAddress(tos), b)
-			if err != nil {
-				log.WithContext(ctx).Warnf("SMTP Send Error! Error:%+v", err)
-			} else {
-				log.WithContext(ctx).Infof("SMTP Send Success !")
-			}
 
-			// 重新选取证书域名
+			// 使用其他方式发送
 			if err != nil {
+				if errors.Is(err, smtp.NoSupportSTARTTLSError) {
+					err = smtp.SendMailWithTls("", domain.mxHost+":465", nil, e.From.EmailAddress, buildAddress(tos), b)
+					if err != nil {
+						log.WithContext(ctx).Warnf("Unsafe! %s Server Not Support SMTPS & STARTTLS", domain.domain)
+						err = smtp.SendMailUnsafe("", domain.mxHost+":25", nil, e.From.EmailAddress, buildAddress(tos), b)
+					}
+				}
+
+				// 证书错误,从新选取证书发送
 				if certificateErr, ok := err.(*tls.CertificateVerificationError); ok {
 					if hostnameErr, is := certificateErr.Err.(x509.HostnameError); is {
 						if hostnameErr.Certificate != nil {
 							certificateHostName := hostnameErr.Certificate.DNSNames
-							// smtps发送失败,尝试smtp
+							// 重新选取证书发送
 							err = smtp.SendMail(domainMatch(domain.domain, certificateHostName), domain.mxHost+":25", nil, e.From.EmailAddress, buildAddress(tos), b)
-							if err != nil {
-								log.WithContext(ctx).Warnf("SMTP Send Error! Error:%+v", err)
-							} else {
-								log.WithContext(ctx).Infof("SMTP Send Success !")
-							}
 						}
 					}
 				}
@@ -208,6 +207,10 @@ func buildAddress(u []*parsemail.User) []string {
 }
 
 func domainMatch(domain string, dnsNames []string) string {
+	if len(dnsNames) == 0 {
+		return domain
+	}
+
 	secondMatch := ""
 
 	for _, name := range dnsNames {

+ 24 - 0
server/utils/send/send_test.go

@@ -1,6 +1,7 @@
 package send
 
 import (
+	"fmt"
 	log "github.com/sirupsen/logrus"
 	"os"
 	"pmail/config"
@@ -49,3 +50,26 @@ func TestSend(t *testing.T) {
 	}
 	Send(nil, e)
 }
+
+func TestSendSohu(t *testing.T) {
+	testInit()
+	e := &parsemail.Email{
+		From: &parsemail.User{
+			Name:         "发送人",
+			EmailAddress: "j@jinnrry.com",
+		},
+		To: []*parsemail.User{
+			{"jinnrry@sohu.com", "名"},
+		},
+		Subject: "插件测试",
+		Text:    []byte("这是Text"),
+		HTML:    []byte("<div>这是Html</div>"),
+	}
+	Send(nil, e)
+}
+
+func Test_domainMatch(t *testing.T) {
+	domain := domainMatch("qq.com", nil)
+
+	fmt.Println(domain)
+}

+ 53 - 1
server/utils/smtp/smtp.go

@@ -33,6 +33,8 @@ import (
 	"time"
 )
 
+var NoSupportSTARTTLSError = errors.New("smtp: server doesn't support STARTTLS")
+
 // A Client represents a client connection to an SMTP server.
 type Client struct {
 	// Text is the textproto.Conn used by the Client. It is exported to allow for
@@ -417,7 +419,7 @@ func SendMail(domain string, addr string, a smtp.Auth, from string, to []string,
 		return err
 	}
 	if ok, _ := c.Extension("STARTTLS"); !ok {
-		return errors.New("smtp: server doesn't support STARTTLS")
+		return NoSupportSTARTTLSError
 	}
 
 	var config *tls.Config
@@ -461,6 +463,56 @@ func SendMail(domain string, addr string, a smtp.Auth, from string, to []string,
 	return c.Quit()
 }
 
+// SendMailUnsafe 无TLS加密的邮件发送方式
+func SendMailUnsafe(domain string, addr string, a smtp.Auth, from string, to []string, msg []byte) error {
+	if err := validateLine(from); err != nil {
+		return err
+	}
+	for _, recp := range to {
+		if err := validateLine(recp); err != nil {
+			return err
+		}
+	}
+	c, err := Dial(addr)
+	if err != nil {
+		return err
+	}
+	defer c.Close()
+	if err = c.hello(); err != nil {
+		return err
+	}
+
+	if a != nil && c.ext != nil {
+		if _, ok := c.ext["AUTH"]; !ok {
+			return errors.New("smtp: server doesn't support AUTH")
+		}
+		if err = c.Auth(a); err != nil {
+			return err
+		}
+	}
+	if err = c.Mail(from); err != nil {
+		return err
+	}
+	for _, addr := range to {
+		if err = c.Rcpt(addr); err != nil {
+			return err
+		}
+	}
+	w, err := c.Data()
+	if err != nil {
+		return err
+	}
+	_, err = w.Write(msg)
+	if err != nil {
+		return err
+	}
+	err = w.Close()
+	if err != nil {
+		return err
+	}
+	return c.Quit()
+}
+
 // Extension reports whether an extension is support by the server.
 // The extension name is case-insensitive. If the extension is supported,
 // Extension also returns a string that contains any parameters the