mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-10-31 06:21:11 +00:00 
			
		
		
		
	Merge pull request #761 from phsmit/mailer_rewritten
Rewrite of SendMail function
This commit is contained in:
		
				commit
				
					
						bb267e30b6
					
				
			
		
					 3 changed files with 49 additions and 19 deletions
				
			
		|  | @ -94,7 +94,10 @@ SUBJECT = %(APP_NAME)s | ||||||
| ; Mail server | ; Mail server | ||||||
| ; Gmail: smtp.gmail.com:587 | ; Gmail: smtp.gmail.com:587 | ||||||
| ; QQ: smtp.qq.com:25 | ; QQ: smtp.qq.com:25 | ||||||
|  | ; Note, if the port ends with "465", SMTPS will be used. Using STARTTLS on port 587 is recommended per RFC 6409. If the server supports STARTTLS it will always be used. | ||||||
| HOST = | HOST = | ||||||
|  | ; Do not verify the certificate of the server. Only use this for self-signed certificates | ||||||
|  | SKIP_VERIFY =  | ||||||
| ; Mail from address | ; Mail from address | ||||||
| FROM = | FROM = | ||||||
| ; Mailer user name and password | ; Mailer user name and password | ||||||
|  |  | ||||||
|  | @ -67,22 +67,53 @@ func processMailQueue() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // sendMail allows mail with self-signed certificates. | // sendMail allows mail with self-signed certificates. | ||||||
| func sendMail(hostAddressWithPort string, auth smtp.Auth, from string, recipients []string, msgContent []byte) error { | func sendMail(settings *setting.Mailer, from string, recipients []string, msgContent []byte) error { | ||||||
| 	client, err := smtp.Dial(hostAddressWithPort) | 	host, port, err := net.SplitHostPort(settings.Host) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	host, _, _ := net.SplitHostPort(hostAddressWithPort) | 	if len(port) == 0 { | ||||||
| 	tlsConn := &tls.Config{ | 		port = "587" | ||||||
| 		InsecureSkipVerify: true, | 	} | ||||||
|  | 
 | ||||||
|  | 	tlsconfig := &tls.Config{ | ||||||
|  | 		InsecureSkipVerify: settings.SkipVerify, | ||||||
| 		ServerName:         host, | 		ServerName:         host, | ||||||
| 	} | 	} | ||||||
| 	if err = client.StartTLS(tlsConn); err != nil { | 
 | ||||||
|  | 	var conn net.Conn | ||||||
|  | 	if conn, err = net.Dial("tcp", net.JoinHostPort(host, port)); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	defer conn.Close() | ||||||
|  | 
 | ||||||
|  | 	connection_secure := false | ||||||
|  | 	// Start TLS directly if the port ends with 465 (SMTPS protocol) | ||||||
|  | 	if strings.HasSuffix(port, "465") { | ||||||
|  | 		conn = tls.Client(conn, tlsconfig) | ||||||
|  | 		connection_secure = true | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var client *smtp.Client | ||||||
|  | 	if client, err = smtp.NewClient(conn, host); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if ok, _ := client.Extension("AUTH"); ok && auth != nil { | 	// If not using SMTPS, alway use STARTTLS if available | ||||||
|  | 	has_starttls, _ := client.Extension("STARTTLS") | ||||||
|  | 	if !connection_secure && has_starttls { | ||||||
|  | 		if err = client.StartTLS(tlsconfig); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	auth_available, _ := client.Extension("AUTH") | ||||||
|  | 
 | ||||||
|  | 	// Possible improvement: only plain authentication is now available. | ||||||
|  | 	// Maybe in future CRAM MD5 as well? | ||||||
|  | 	if auth_available && len(settings.User) > 0 { | ||||||
|  | 		auth := smtp.PlainAuth("", settings.User, settings.Passwd, host) | ||||||
| 		if err = client.Auth(auth); err != nil { | 		if err = client.Auth(auth); err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
|  | @ -116,7 +147,6 @@ func sendMail(hostAddressWithPort string, auth smtp.Auth, from string, recipient | ||||||
| // Direct Send mail message | // Direct Send mail message | ||||||
| func Send(msg *Message) (int, error) { | func Send(msg *Message) (int, error) { | ||||||
| 	log.Trace("Sending mails to: %s", strings.Join(msg.To, "; ")) | 	log.Trace("Sending mails to: %s", strings.Join(msg.To, "; ")) | ||||||
| 	host := strings.Split(setting.MailService.Host, ":") |  | ||||||
| 
 | 
 | ||||||
| 	// get message body | 	// get message body | ||||||
| 	content := msg.Content() | 	content := msg.Content() | ||||||
|  | @ -127,17 +157,12 @@ func Send(msg *Message) (int, error) { | ||||||
| 		return 0, fmt.Errorf("empty email body") | 		return 0, fmt.Errorf("empty email body") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	var auth smtp.Auth |  | ||||||
| 	if len(setting.MailService.Passwd) > 0 { |  | ||||||
| 		auth = smtp.PlainAuth("", setting.MailService.User, setting.MailService.Passwd, host[0]) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if msg.Massive { | 	if msg.Massive { | ||||||
| 		// send mail to multiple emails one by one | 		// send mail to multiple emails one by one | ||||||
| 		num := 0 | 		num := 0 | ||||||
| 		for _, to := range msg.To { | 		for _, to := range msg.To { | ||||||
| 			body := []byte("To: " + to + "\r\n" + content) | 			body := []byte("To: " + to + "\r\n" + content) | ||||||
| 			err := sendMail(setting.MailService.Host, auth, msg.From, []string{to}, body) | 			err := sendMail(setting.MailService, msg.From, []string{to}, body) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return num, err | 				return num, err | ||||||
| 			} | 			} | ||||||
|  | @ -148,7 +173,7 @@ func Send(msg *Message) (int, error) { | ||||||
| 		body := []byte("To: " + strings.Join(msg.To, ";") + "\r\n" + content) | 		body := []byte("To: " + strings.Join(msg.To, ";") + "\r\n" + content) | ||||||
| 
 | 
 | ||||||
| 		// send to multiple emails in one message | 		// send to multiple emails in one message | ||||||
| 		err := sendMail(setting.MailService.Host, auth, msg.From, msg.To, body) | 		err := sendMail(setting.MailService, msg.From, msg.To, body) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return 0, err | 			return 0, err | ||||||
| 		} else { | 		} else { | ||||||
|  |  | ||||||
|  | @ -437,6 +437,7 @@ type Mailer struct { | ||||||
| 	Host         string | 	Host         string | ||||||
| 	From         string | 	From         string | ||||||
| 	User, Passwd string | 	User, Passwd string | ||||||
|  | 	SkipVerify   bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type OauthInfo struct { | type OauthInfo struct { | ||||||
|  | @ -463,10 +464,11 @@ func newMailService() { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	MailService = &Mailer{ | 	MailService = &Mailer{ | ||||||
| 		Name:   Cfg.MustValue("mailer", "NAME", AppName), | 		Name:       Cfg.MustValue("mailer", "NAME", AppName), | ||||||
| 		Host:   Cfg.MustValue("mailer", "HOST"), | 		Host:       Cfg.MustValue("mailer", "HOST"), | ||||||
| 		User:   Cfg.MustValue("mailer", "USER"), | 		User:       Cfg.MustValue("mailer", "USER"), | ||||||
| 		Passwd: Cfg.MustValue("mailer", "PASSWD"), | 		Passwd:     Cfg.MustValue("mailer", "PASSWD"), | ||||||
|  | 		SkipVerify: Cfg.MustBool("mailer", "SKIP_VERIFY", false), | ||||||
| 	} | 	} | ||||||
| 	MailService.From = Cfg.MustValue("mailer", "FROM", MailService.User) | 	MailService.From = Cfg.MustValue("mailer", "FROM", MailService.User) | ||||||
| 	log.Info("Mail Service Enabled") | 	log.Info("Mail Service Enabled") | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue