2019-02-10 04:37:37 +03:00
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package setting
import (
Rework mailer settings (#18982)
* `PROTOCOL`: can be smtp, smtps, smtp+startls, smtp+unix, sendmail, dummy
* `SMTP_ADDR`: domain for SMTP, or path to unix socket
* `SMTP_PORT`: port for SMTP; defaults to 25 for `smtp`, 465 for `smtps`, and 587 for `smtp+startls`
* `ENABLE_HELO`, `HELO_HOSTNAME`: reverse `DISABLE_HELO` to `ENABLE_HELO`; default to false + system hostname
* `FORCE_TRUST_SERVER_CERT`: replace the unclear `SKIP_VERIFY`
* `CLIENT_CERT_FILE`, `CLIENT_KEY_FILE`, `USE_CLIENT_CERT`: clarify client certificates here
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-08-02 08:24:18 +03:00
"net"
2019-02-10 04:37:37 +03:00
"net/mail"
Rework mailer settings (#18982)
* `PROTOCOL`: can be smtp, smtps, smtp+startls, smtp+unix, sendmail, dummy
* `SMTP_ADDR`: domain for SMTP, or path to unix socket
* `SMTP_PORT`: port for SMTP; defaults to 25 for `smtp`, 465 for `smtps`, and 587 for `smtp+startls`
* `ENABLE_HELO`, `HELO_HOSTNAME`: reverse `DISABLE_HELO` to `ENABLE_HELO`; default to false + system hostname
* `FORCE_TRUST_SERVER_CERT`: replace the unclear `SKIP_VERIFY`
* `CLIENT_CERT_FILE`, `CLIENT_KEY_FILE`, `USE_CLIENT_CERT`: clarify client certificates here
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-08-02 08:24:18 +03:00
"strings"
2020-05-03 02:04:31 +03:00
"time"
2019-02-10 04:37:37 +03:00
"code.gitea.io/gitea/modules/log"
2019-08-23 19:40:30 +03:00
2019-02-10 04:37:37 +03:00
shellquote "github.com/kballard/go-shellquote"
)
// Mailer represents mail service.
type Mailer struct {
// Mailer
2021-11-19 18:35:20 +03:00
Name string
From string
EnvelopeFrom string
OverrideEnvelopeFrom bool ` ini:"-" `
FromName string
FromEmail string
SendAsPlainText bool
SubjectPrefix string
2019-02-10 04:37:37 +03:00
// SMTP sender
Rework mailer settings (#18982)
* `PROTOCOL`: can be smtp, smtps, smtp+startls, smtp+unix, sendmail, dummy
* `SMTP_ADDR`: domain for SMTP, or path to unix socket
* `SMTP_PORT`: port for SMTP; defaults to 25 for `smtp`, 465 for `smtps`, and 587 for `smtp+startls`
* `ENABLE_HELO`, `HELO_HOSTNAME`: reverse `DISABLE_HELO` to `ENABLE_HELO`; default to false + system hostname
* `FORCE_TRUST_SERVER_CERT`: replace the unclear `SKIP_VERIFY`
* `CLIENT_CERT_FILE`, `CLIENT_KEY_FILE`, `USE_CLIENT_CERT`: clarify client certificates here
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-08-02 08:24:18 +03:00
Protocol string
SMTPAddr string
SMTPPort string
User , Passwd string
EnableHelo bool
HeloHostname string
ForceTrustServerCert bool
UseClientCert bool
ClientCertFile string
ClientKeyFile string
2019-02-10 04:37:37 +03:00
// Sendmail sender
2022-01-06 03:43:45 +03:00
SendmailPath string
SendmailArgs [ ] string
SendmailTimeout time . Duration
SendmailConvertCRLF bool
2019-02-10 04:37:37 +03:00
}
2022-01-20 20:46:10 +03:00
// MailService the global mailer
var MailService * Mailer
2019-02-10 04:37:37 +03:00
func newMailService ( ) {
sec := Cfg . Section ( "mailer" )
// Check mailer setting.
if ! sec . Key ( "ENABLED" ) . MustBool ( ) {
return
}
MailService = & Mailer {
Name : sec . Key ( "NAME" ) . MustString ( AppName ) ,
SendAsPlainText : sec . Key ( "SEND_AS_PLAIN_TEXT" ) . MustBool ( false ) ,
Rework mailer settings (#18982)
* `PROTOCOL`: can be smtp, smtps, smtp+startls, smtp+unix, sendmail, dummy
* `SMTP_ADDR`: domain for SMTP, or path to unix socket
* `SMTP_PORT`: port for SMTP; defaults to 25 for `smtp`, 465 for `smtps`, and 587 for `smtp+startls`
* `ENABLE_HELO`, `HELO_HOSTNAME`: reverse `DISABLE_HELO` to `ENABLE_HELO`; default to false + system hostname
* `FORCE_TRUST_SERVER_CERT`: replace the unclear `SKIP_VERIFY`
* `CLIENT_CERT_FILE`, `CLIENT_KEY_FILE`, `USE_CLIENT_CERT`: clarify client certificates here
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-08-02 08:24:18 +03:00
Protocol : sec . Key ( "PROTOCOL" ) . In ( "" , [ ] string { "smtp" , "smtps" , "smtp+startls" , "smtp+unix" , "sendmail" , "dummy" } ) ,
SMTPAddr : sec . Key ( "SMTP_ADDR" ) . String ( ) ,
SMTPPort : sec . Key ( "SMTP_PORT" ) . String ( ) ,
User : sec . Key ( "USER" ) . String ( ) ,
Passwd : sec . Key ( "PASSWD" ) . String ( ) ,
EnableHelo : sec . Key ( "ENABLE_HELO" ) . MustBool ( true ) ,
HeloHostname : sec . Key ( "HELO_HOSTNAME" ) . String ( ) ,
ForceTrustServerCert : sec . Key ( "FORCE_TRUST_SERVER_CERT" ) . MustBool ( false ) ,
UseClientCert : sec . Key ( "USE_CLIENT_CERT" ) . MustBool ( false ) ,
ClientCertFile : sec . Key ( "CLIENT_CERT_FILE" ) . String ( ) ,
ClientKeyFile : sec . Key ( "CLIENT_KEY_FILE" ) . String ( ) ,
SubjectPrefix : sec . Key ( "SUBJECT_PREFIX" ) . MustString ( "" ) ,
2019-02-10 04:37:37 +03:00
2022-01-06 03:43:45 +03:00
SendmailPath : sec . Key ( "SENDMAIL_PATH" ) . MustString ( "sendmail" ) ,
SendmailTimeout : sec . Key ( "SENDMAIL_TIMEOUT" ) . MustDuration ( 5 * time . Minute ) ,
SendmailConvertCRLF : sec . Key ( "SENDMAIL_CONVERT_CRLF" ) . MustBool ( true ) ,
2019-02-10 04:37:37 +03:00
}
MailService . From = sec . Key ( "FROM" ) . MustString ( MailService . User )
2021-11-19 18:35:20 +03:00
MailService . EnvelopeFrom = sec . Key ( "ENVELOPE_FROM" ) . MustString ( "" )
2019-02-10 04:37:37 +03:00
Rework mailer settings (#18982)
* `PROTOCOL`: can be smtp, smtps, smtp+startls, smtp+unix, sendmail, dummy
* `SMTP_ADDR`: domain for SMTP, or path to unix socket
* `SMTP_PORT`: port for SMTP; defaults to 25 for `smtp`, 465 for `smtps`, and 587 for `smtp+startls`
* `ENABLE_HELO`, `HELO_HOSTNAME`: reverse `DISABLE_HELO` to `ENABLE_HELO`; default to false + system hostname
* `FORCE_TRUST_SERVER_CERT`: replace the unclear `SKIP_VERIFY`
* `CLIENT_CERT_FILE`, `CLIENT_KEY_FILE`, `USE_CLIENT_CERT`: clarify client certificates here
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-08-02 08:24:18 +03:00
// FIXME: DEPRECATED to be removed in v1.19.0
deprecatedSetting ( "mailer" , "MAILER_TYPE" , "mailer" , "PROTOCOL" )
if sec . HasKey ( "MAILER_TYPE" ) && ! sec . HasKey ( "PROTOCOL" ) {
if sec . Key ( "MAILER_TYPE" ) . String ( ) == "sendmail" {
MailService . Protocol = "sendmail"
}
2019-02-10 04:37:37 +03:00
}
Rework mailer settings (#18982)
* `PROTOCOL`: can be smtp, smtps, smtp+startls, smtp+unix, sendmail, dummy
* `SMTP_ADDR`: domain for SMTP, or path to unix socket
* `SMTP_PORT`: port for SMTP; defaults to 25 for `smtp`, 465 for `smtps`, and 587 for `smtp+startls`
* `ENABLE_HELO`, `HELO_HOSTNAME`: reverse `DISABLE_HELO` to `ENABLE_HELO`; default to false + system hostname
* `FORCE_TRUST_SERVER_CERT`: replace the unclear `SKIP_VERIFY`
* `CLIENT_CERT_FILE`, `CLIENT_KEY_FILE`, `USE_CLIENT_CERT`: clarify client certificates here
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-08-02 08:24:18 +03:00
// FIXME: DEPRECATED to be removed in v1.19.0
deprecatedSetting ( "mailer" , "HOST" , "mailer" , "SMTP_ADDR" )
if sec . HasKey ( "HOST" ) && ! sec . HasKey ( "SMTP_ADDR" ) {
givenHost := sec . Key ( "HOST" ) . String ( )
addr , port , err := net . SplitHostPort ( givenHost )
if err != nil {
log . Fatal ( "Invalid mailer.HOST (%s): %v" , givenHost , err )
2019-02-10 04:37:37 +03:00
}
Rework mailer settings (#18982)
* `PROTOCOL`: can be smtp, smtps, smtp+startls, smtp+unix, sendmail, dummy
* `SMTP_ADDR`: domain for SMTP, or path to unix socket
* `SMTP_PORT`: port for SMTP; defaults to 25 for `smtp`, 465 for `smtps`, and 587 for `smtp+startls`
* `ENABLE_HELO`, `HELO_HOSTNAME`: reverse `DISABLE_HELO` to `ENABLE_HELO`; default to false + system hostname
* `FORCE_TRUST_SERVER_CERT`: replace the unclear `SKIP_VERIFY`
* `CLIENT_CERT_FILE`, `CLIENT_KEY_FILE`, `USE_CLIENT_CERT`: clarify client certificates here
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-08-02 08:24:18 +03:00
MailService . SMTPAddr = addr
MailService . SMTPPort = port
2019-02-10 04:37:37 +03:00
}
Rework mailer settings (#18982)
* `PROTOCOL`: can be smtp, smtps, smtp+startls, smtp+unix, sendmail, dummy
* `SMTP_ADDR`: domain for SMTP, or path to unix socket
* `SMTP_PORT`: port for SMTP; defaults to 25 for `smtp`, 465 for `smtps`, and 587 for `smtp+startls`
* `ENABLE_HELO`, `HELO_HOSTNAME`: reverse `DISABLE_HELO` to `ENABLE_HELO`; default to false + system hostname
* `FORCE_TRUST_SERVER_CERT`: replace the unclear `SKIP_VERIFY`
* `CLIENT_CERT_FILE`, `CLIENT_KEY_FILE`, `USE_CLIENT_CERT`: clarify client certificates here
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-08-02 08:24:18 +03:00
// FIXME: DEPRECATED to be removed in v1.19.0
deprecatedSetting ( "mailer" , "IS_TLS_ENABLED" , "mailer" , "PROTOCOL" )
if sec . HasKey ( "IS_TLS_ENABLED" ) && ! sec . HasKey ( "PROTOCOL" ) {
if sec . Key ( "IS_TLS_ENABLED" ) . MustBool ( ) {
MailService . Protocol = "smtps"
} else {
MailService . Protocol = "smtp+startls"
}
}
if MailService . SMTPPort == "" {
switch MailService . Protocol {
case "smtp" :
MailService . SMTPPort = "25"
case "smtps" :
MailService . SMTPPort = "465"
case "smtp+startls" :
MailService . SMTPPort = "587"
}
}
if MailService . Protocol == "" {
if strings . ContainsAny ( MailService . SMTPAddr , "/\\" ) {
MailService . Protocol = "smtp+unix"
} else {
switch MailService . SMTPPort {
case "25" :
MailService . Protocol = "smtp"
case "465" :
MailService . Protocol = "smtps"
case "587" :
MailService . Protocol = "smtp+startls"
default :
log . Error ( "unable to infer unspecified mailer.PROTOCOL from mailer.SMTP_PORT = %q, assume using smtps" , MailService . SMTPPort )
MailService . Protocol = "smtps"
}
}
}
// we want to warn if users use SMTP on a non-local IP;
// we might as well take the opportunity to check that it has an IP at all
ips := tryResolveAddr ( MailService . SMTPAddr )
if MailService . Protocol == "smtp" {
for _ , ip := range ips {
if ! ip . IsLoopback ( ) {
log . Warn ( "connecting over insecure SMTP protocol to non-local address is not recommended" )
break
}
}
}
// FIXME: DEPRECATED to be removed in v1.19.0
deprecatedSetting ( "mailer" , "DISABLE_HELO" , "mailer" , "ENABLE_HELO" )
if sec . HasKey ( "DISABLE_HELO" ) && ! sec . HasKey ( "ENABLE_HELO" ) {
MailService . EnableHelo = ! sec . Key ( "DISABLE_HELO" ) . MustBool ( )
}
// FIXME: DEPRECATED to be removed in v1.19.0
deprecatedSetting ( "mailer" , "SKIP_VERIFY" , "mailer" , "FORCE_TRUST_SERVER_CERT" )
if sec . HasKey ( "SKIP_VERIFY" ) && ! sec . HasKey ( "FORCE_TRUST_SERVER_CERT" ) {
MailService . ForceTrustServerCert = sec . Key ( "SKIP_VERIFY" ) . MustBool ( )
}
// FIXME: DEPRECATED to be removed in v1.19.0
deprecatedSetting ( "mailer" , "USE_CERTIFICATE" , "mailer" , "USE_CLIENT_CERT" )
if sec . HasKey ( "USE_CERTIFICATE" ) && ! sec . HasKey ( "USE_CLIENT_CERT" ) {
MailService . UseClientCert = sec . Key ( "USE_CLIENT_CERT" ) . MustBool ( )
}
// FIXME: DEPRECATED to be removed in v1.19.0
deprecatedSetting ( "mailer" , "CERT_FILE" , "mailer" , "CLIENT_CERT_FILE" )
if sec . HasKey ( "CERT_FILE" ) && ! sec . HasKey ( "CLIENT_CERT_FILE" ) {
MailService . ClientCertFile = sec . Key ( "CERT_FILE" ) . String ( )
}
// FIXME: DEPRECATED to be removed in v1.19.0
deprecatedSetting ( "mailer" , "KEY_FILE" , "mailer" , "CLIENT_KEY_FILE" )
if sec . HasKey ( "KEY_FILE" ) && ! sec . HasKey ( "CLIENT_KEY_FILE" ) {
MailService . ClientKeyFile = sec . Key ( "KEY_FILE" ) . String ( )
}
// FIXME: DEPRECATED to be removed in v1.19.0
deprecatedSetting ( "mailer" , "ENABLE_HTML_ALTERNATIVE" , "mailer" , "SEND_AS_PLAIN_TEXT" )
if sec . HasKey ( "ENABLE_HTML_ALTERNATIVE" ) && ! sec . HasKey ( "SEND_AS_PLAIN_TEXT" ) {
MailService . SendAsPlainText = ! sec . Key ( "ENABLE_HTML_ALTERNATIVE" ) . MustBool ( false )
}
if MailService . From != "" {
parsed , err := mail . ParseAddress ( MailService . From )
if err != nil {
log . Fatal ( "Invalid mailer.FROM (%s): %v" , MailService . From , err )
}
MailService . FromName = parsed . Name
MailService . FromEmail = parsed . Address
} else {
log . Error ( "no mailer.FROM provided, email system may not work." )
2019-02-10 04:37:37 +03:00
}
2021-11-19 18:35:20 +03:00
switch MailService . EnvelopeFrom {
case "" :
MailService . OverrideEnvelopeFrom = false
case "<>" :
MailService . EnvelopeFrom = ""
MailService . OverrideEnvelopeFrom = true
default :
Rework mailer settings (#18982)
* `PROTOCOL`: can be smtp, smtps, smtp+startls, smtp+unix, sendmail, dummy
* `SMTP_ADDR`: domain for SMTP, or path to unix socket
* `SMTP_PORT`: port for SMTP; defaults to 25 for `smtp`, 465 for `smtps`, and 587 for `smtp+startls`
* `ENABLE_HELO`, `HELO_HOSTNAME`: reverse `DISABLE_HELO` to `ENABLE_HELO`; default to false + system hostname
* `FORCE_TRUST_SERVER_CERT`: replace the unclear `SKIP_VERIFY`
* `CLIENT_CERT_FILE`, `CLIENT_KEY_FILE`, `USE_CLIENT_CERT`: clarify client certificates here
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-08-02 08:24:18 +03:00
parsed , err := mail . ParseAddress ( MailService . EnvelopeFrom )
2021-11-19 18:35:20 +03:00
if err != nil {
log . Fatal ( "Invalid mailer.ENVELOPE_FROM (%s): %v" , MailService . EnvelopeFrom , err )
}
MailService . OverrideEnvelopeFrom = true
MailService . EnvelopeFrom = parsed . Address
}
Rework mailer settings (#18982)
* `PROTOCOL`: can be smtp, smtps, smtp+startls, smtp+unix, sendmail, dummy
* `SMTP_ADDR`: domain for SMTP, or path to unix socket
* `SMTP_PORT`: port for SMTP; defaults to 25 for `smtp`, 465 for `smtps`, and 587 for `smtp+startls`
* `ENABLE_HELO`, `HELO_HOSTNAME`: reverse `DISABLE_HELO` to `ENABLE_HELO`; default to false + system hostname
* `FORCE_TRUST_SERVER_CERT`: replace the unclear `SKIP_VERIFY`
* `CLIENT_CERT_FILE`, `CLIENT_KEY_FILE`, `USE_CLIENT_CERT`: clarify client certificates here
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-08-02 08:24:18 +03:00
if MailService . Protocol == "sendmail" {
var err error
2019-02-10 04:37:37 +03:00
MailService . SendmailArgs , err = shellquote . Split ( sec . Key ( "SENDMAIL_ARGS" ) . String ( ) )
if err != nil {
2019-04-02 10:48:31 +03:00
log . Error ( "Failed to parse Sendmail args: %s with error %v" , CustomConf , err )
2019-02-10 04:37:37 +03:00
}
}
log . Info ( "Mail Service Enabled" )
}
func newRegisterMailService ( ) {
if ! Cfg . Section ( "service" ) . Key ( "REGISTER_EMAIL_CONFIRM" ) . MustBool ( ) {
return
} else if MailService == nil {
log . Warn ( "Register Mail Service: Mail Service is not enabled" )
return
}
Service . RegisterEmailConfirm = true
log . Info ( "Register Mail Service Enabled" )
}
func newNotifyMailService ( ) {
if ! Cfg . Section ( "service" ) . Key ( "ENABLE_NOTIFY_MAIL" ) . MustBool ( ) {
return
} else if MailService == nil {
log . Warn ( "Notify Mail Service: Mail Service is not enabled" )
return
}
Service . EnableNotifyMail = true
log . Info ( "Notify Mail Service Enabled" )
}
Rework mailer settings (#18982)
* `PROTOCOL`: can be smtp, smtps, smtp+startls, smtp+unix, sendmail, dummy
* `SMTP_ADDR`: domain for SMTP, or path to unix socket
* `SMTP_PORT`: port for SMTP; defaults to 25 for `smtp`, 465 for `smtps`, and 587 for `smtp+startls`
* `ENABLE_HELO`, `HELO_HOSTNAME`: reverse `DISABLE_HELO` to `ENABLE_HELO`; default to false + system hostname
* `FORCE_TRUST_SERVER_CERT`: replace the unclear `SKIP_VERIFY`
* `CLIENT_CERT_FILE`, `CLIENT_KEY_FILE`, `USE_CLIENT_CERT`: clarify client certificates here
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-08-02 08:24:18 +03:00
func tryResolveAddr ( addr string ) [ ] net . IP {
if strings . HasPrefix ( addr , "[" ) && strings . HasSuffix ( addr , "]" ) {
addr = addr [ 1 : len ( addr ) - 1 ]
}
ip := net . ParseIP ( addr )
if ip != nil {
ips := make ( [ ] net . IP , 1 )
ips [ 0 ] = ip
return ips
}
ips , err := net . LookupIP ( addr )
if err != nil {
log . Warn ( "could not look up mailer.SMTP_ADDR: %v" , err )
return make ( [ ] net . IP , 0 )
}
return ips
}