Ver código fonte

conf: overhaul email settings (#5940)

ᴜɴᴋɴᴡᴏɴ 4 anos atrás
pai
commit
52ffb67b33

+ 1 - 0
CHANGELOG.md

@@ -22,6 +22,7 @@ All notable changes to Gogs are documented in this file.
 - Configuration option `[server] LANDING_PAGE` is deprecated and will end support in 0.13.0, please start using `[server] LANDING_URL`.
 - Configuration option `[database] DB_TYPE` is deprecated and will end support in 0.13.0, please start using `[database] TYPE`.
 - Configuration option `[database] PASSWD` is deprecated and will end support in 0.13.0, please start using `[database] PASSWORD`.
+- Configuration section `[mailer]` is deprecated and will end support in 0.13.0, please start using `[email]`.
 
 ### Fixed
 

+ 2 - 5
Makefile

@@ -71,11 +71,8 @@ less: public/css/gogs.css
 public/css/gogs.css: $(LESS_FILES)
 	@type lessc >/dev/null 2>&1 && lessc --source-map "public/less/gogs.less" $@ || echo "lessc command not found or failed"
 
-clean:
-	go clean -i ./...
-
-clean-mac: clean
-	find . -name ".DS_Store" -print0 | xargs -0 rm
+clean-mac:
+	find . -name "*.DS_Store" -type f -delete
 
 test:
 	go test -cover -race ./...

+ 34 - 31
conf/app.ini

@@ -167,6 +167,40 @@ ENABLE_LOGIN_STATUS_COOKIE = false
 ; The cookie name to store user login status.
 LOGIN_STATUS_COOKIE_NAME = login_status
 
+[email]
+; Whether to enable the email service.
+ENABLED = false
+; The prefix prepended to the subject line.
+SUBJECT_PREFIX = `[%(BRAND_NAME)s] `
+; The SMTP server with its port, e.g. smtp.mailgun.org:587, smtp.gmail.com:587, smtp.qq.com:465
+; If the port ends is "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 = smtp.mailgun.org:587
+; The email from address (RFC 5322). This can be just an email address, or the `"Name" <email@example.com>` format.
+FROM = noreply@gogs.localhost
+; The login user.
+USER = noreply@gogs.localhost
+; The login password.
+PASSWORD =
+
+; Whether to disable HELO operation when the hostname is different.
+DISABLE_HELO =
+; The custom hostname for HELO operation, default is from system.
+HELO_HOSTNAME =
+
+; Whether to skip verifying the certificate of the server. Only use this for self-signed certificates.
+SKIP_VERIFY = false
+; Whether to use client certificates.
+USE_CERTIFICATE = false
+CERT_FILE = custom/email/cert.pem
+KEY_FILE = custom/email/key.pem
+
+; Whether to use "text/plain" as content format.
+USE_PLAIN_TEXT = false
+; Whether to attach a plaintext alternative to the MIME message while sending HTML emails.
+; It is used to support older mail clients and make spam filters happier.
+ADD_PLAIN_TEXT_ALT = false
+
 ; Attachment settings for releases
 [release.attachment]
 ; Whether attachments are enabled. Defaults to `true`
@@ -234,37 +268,6 @@ SKIP_TLS_VERIFY = false
 ; Number of history information in each page
 PAGING_NUM = 10
 
-[mailer]
-ENABLED = false
-; Buffer length of channel, keep it as it is if you don't know what it is.
-SEND_BUFFER_LEN = 100
-; Prefix prepended to the subject line
-SUBJECT_PREFIX = `[%(BRAND_NAME)s] `
-; Mail server
-; Gmail: smtp.gmail.com:587
-; QQ: smtp.qq.com:465
-; 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 =
-; Disable HELO operation when hostname are different.
-DISABLE_HELO =
-; Custom hostname for HELO operation, default is from system.
-HELO_HOSTNAME =
-; Do not verify the certificate of the server. Only use this for self-signed certificates
-SKIP_VERIFY =
-; Use client certificate
-USE_CERTIFICATE = false
-CERT_FILE = custom/mailer/cert.pem
-KEY_FILE = custom/mailer/key.pem
-; Mail from address, RFC 5322. This can be just an email address, or the `"Name" <email@example.com>` format
-FROM =
-; Mailer user name and password
-USER =
-PASSWD =
-; Use text/plain as format of content
-USE_PLAIN_TEXT = false
-; If sending html emails, then also attach a plaintext alternative to the MIME message, to support older mail clients and make spam filters happier.
-ADD_PLAIN_TEXT_ALT = false
-
 [cache]
 ; Either "memory", "redis", or "memcache", default is "memory"
 ADAPTER = memory

+ 18 - 10
conf/locale/locale_en-US.ini

@@ -1235,6 +1235,24 @@ config.security.reverse_proxy_auth_user = Reverse proxy authentication header
 config.security.enable_login_status_cookie = Enable login status cookie
 config.security.login_status_cookie_name = Login status cookie
 
+config.email_config = Email configuration
+config.email.enabled = Enabled
+config.email.subject_prefix = Subject prefix
+config.email.host = Host
+config.email.from = From
+config.email.user = User
+config.email.disable_helo = Disable HELO
+config.email.helo_hostname = HELO hostname
+config.email.skip_verify = Skip certificate verify
+config.email.use_certificate = Use custom certificate
+config.email.cert_file = Certificate file
+config.email.key_file = Key file
+config.email.use_plain_text = Use plain text
+config.email.add_plain_text_alt = Add plain text alternative
+config.email.send_test_mail = Send test email
+config.email.test_mail_failed = Failed to send test email to '%s': %v
+config.email.test_mail_sent = Test email has been sent to '%s'.
+
 config.log_file_root_path = Log File Root Path
 
 config.http_config = HTTP Configuration
@@ -1256,16 +1274,6 @@ config.queue_length = Queue Length
 config.deliver_timeout = Deliver Timeout
 config.skip_tls_verify = Skip TLS Verify
 
-config.mailer_config = Mailer Configuration
-config.mailer_enabled = Enabled
-config.mailer_disable_helo = Disable HELO
-config.mailer_subject_prefix = Subject Prefix
-config.mailer_host = Host
-config.mailer_user = User
-config.send_test_mail = Send Test Email
-config.test_mail_failed = Failed to send test email to '%s': %v
-config.test_mail_sent = Test email has been sent to '%s'.
-
 config.oauth_config = OAuth Configuration
 config.oauth_enabled = Enabled
 

Diferenças do arquivo suprimidas por serem muito extensas
+ 2 - 2
internal/assets/conf/conf_gen.go


Diferenças do arquivo suprimidas por serem muito extensas
+ 3 - 3
internal/assets/public/public_gen.go


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 1
internal/assets/templates/templates_gen.go


+ 2 - 2
internal/cmd/hook.go

@@ -24,7 +24,7 @@ import (
 	"gogs.io/gogs/internal/db"
 	"gogs.io/gogs/internal/db/errors"
 	"gogs.io/gogs/internal/httplib"
-	"gogs.io/gogs/internal/mailer"
+	"gogs.io/gogs/internal/email"
 	"gogs.io/gogs/internal/template"
 )
 
@@ -199,7 +199,7 @@ func runHookPostReceive(c *cli.Context) error {
 	// Post-receive hook does more than just gather Git information,
 	// so we need to setup additional services for email notifications.
 	conf.NewPostReceiveHookServices()
-	mailer.NewContext()
+	email.NewContext()
 
 	isWiki := strings.Contains(os.Getenv(db.ENV_REPO_CUSTOM_HOOKS_PATH), ".wiki.git/")
 

+ 26 - 65
internal/conf/conf.go

@@ -208,6 +208,30 @@ func Init(customConf string) error {
 		}
 	}
 
+	// **************************
+	// ----- Email settings -----
+	// **************************
+
+	if err = File.Section("email").MapTo(&Email); err != nil {
+		return errors.Wrap(err, "mapping [email] section")
+	}
+	// LEGACY [0.13]: In case there are values with old section name.
+	if err = File.Section("mailer").MapTo(&Email); err != nil {
+		return errors.Wrap(err, "mapping [mailer] section")
+	}
+
+	if Email.Enabled {
+		if Email.From == "" {
+			Email.From = Email.User
+		}
+
+		parsed, err := mail.ParseAddress(Email.From)
+		if err != nil {
+			return errors.Wrapf(err, "parse mail address %q", Email.From)
+		}
+		Email.FromEmail = parsed.Address
+	}
+
 	handleDeprecated()
 
 	// TODO
@@ -689,71 +713,10 @@ func newSessionService() {
 	log.Trace("Session service is enabled")
 }
 
-// Mailer represents mail service.
-type Mailer struct {
-	QueueLength       int
-	SubjectPrefix     string
-	Host              string
-	From              string
-	FromEmail         string
-	User, Passwd      string
-	DisableHelo       bool
-	HeloHostname      string
-	SkipVerify        bool
-	UseCertificate    bool
-	CertFile, KeyFile string
-	UsePlainText      bool
-	AddPlainTextAlt   bool
-}
-
-var (
-	MailService *Mailer
-)
-
-// newMailService initializes mail service options from configuration.
-// No non-error log will be printed in hook mode.
-func newMailService() {
-	sec := File.Section("mailer")
-	if !sec.Key("ENABLED").MustBool() {
-		return
-	}
-
-	MailService = &Mailer{
-		QueueLength:     sec.Key("SEND_BUFFER_LEN").MustInt(100),
-		SubjectPrefix:   sec.Key("SUBJECT_PREFIX").MustString("[" + App.BrandName + "] "),
-		Host:            sec.Key("HOST").String(),
-		User:            sec.Key("USER").String(),
-		Passwd:          sec.Key("PASSWD").String(),
-		DisableHelo:     sec.Key("DISABLE_HELO").MustBool(),
-		HeloHostname:    sec.Key("HELO_HOSTNAME").String(),
-		SkipVerify:      sec.Key("SKIP_VERIFY").MustBool(),
-		UseCertificate:  sec.Key("USE_CERTIFICATE").MustBool(),
-		CertFile:        sec.Key("CERT_FILE").String(),
-		KeyFile:         sec.Key("KEY_FILE").String(),
-		UsePlainText:    sec.Key("USE_PLAIN_TEXT").MustBool(),
-		AddPlainTextAlt: sec.Key("ADD_PLAIN_TEXT_ALT").MustBool(),
-	}
-	MailService.From = sec.Key("FROM").MustString(MailService.User)
-
-	if len(MailService.From) > 0 {
-		parsed, err := mail.ParseAddress(MailService.From)
-		if err != nil {
-			log.Fatal("Failed to parse value %q for '[mailer] FROM': %v", MailService.From, err)
-			return
-		}
-		MailService.FromEmail = parsed.Address
-	}
-
-	if HookMode {
-		return
-	}
-	log.Trace("Mail service is enabled")
-}
-
 func newRegisterMailService() {
 	if !File.Section("service").Key("REGISTER_EMAIL_CONFIRM").MustBool() {
 		return
-	} else if MailService == nil {
+	} else if !Email.Enabled {
 		log.Warn("Email confirmation is not enabled due to the mail service is not available")
 		return
 	}
@@ -766,7 +729,7 @@ func newRegisterMailService() {
 func newNotifyMailService() {
 	if !File.Section("service").Key("ENABLE_NOTIFY_MAIL").MustBool() {
 		return
-	} else if MailService == nil {
+	} else if !Email.Enabled {
 		log.Warn("Email notification is not enabled due to the mail service is not available")
 		return
 	}
@@ -786,7 +749,6 @@ func NewServices() {
 	newService()
 	newCacheService()
 	newSessionService()
-	newMailService()
 	newRegisterMailService()
 	newNotifyMailService()
 }
@@ -799,6 +761,5 @@ var HookMode bool
 func NewPostReceiveHookServices() {
 	HookMode = true
 	newService()
-	newMailService()
 	newNotifyMailService()
 }

+ 32 - 0
internal/conf/static.go

@@ -152,6 +152,33 @@ var (
 		EnableLoginStatusCookie        bool
 		LoginStatusCookieName          string
 	}
+
+	// Email settings
+	Email struct {
+		Enabled       bool
+		SubjectPrefix string
+		Host          string
+		From          string
+		User          string
+		Password      string
+
+		DisableHELO  bool   `ini:"DISABLE_HELO"`
+		HELOHostname string `ini:"HELO_HOSTNAME"`
+
+		SkipVerify     bool
+		UseCertificate bool
+		CertFile       string
+		KeyFile        string
+
+		UsePlainText    bool
+		AddPlainTextAlt bool
+
+		// Derived from other static values
+		FromEmail string `ini:"-"` // Parsed email address of From without person's name.
+
+		// Deprecated: Use Password instead, will be removed in 0.13.
+		Passwd string
+	}
 )
 
 // handleDeprecated transfers deprecated values to the new ones when set.
@@ -178,4 +205,9 @@ func handleDeprecated() {
 		Database.Password = Database.Passwd
 		Database.Passwd = ""
 	}
+
+	if Email.Passwd != "" {
+		Email.Password = Email.Passwd
+		Email.Passwd = ""
+	}
 }

+ 6 - 6
internal/db/issue_mail.go

@@ -10,7 +10,7 @@ import (
 	"github.com/unknwon/com"
 	log "unknwon.dev/clog/v2"
 
-	"gogs.io/gogs/internal/mailer"
+	"gogs.io/gogs/internal/email"
 	"gogs.io/gogs/internal/markup"
 	"gogs.io/gogs/internal/conf"
 )
@@ -44,7 +44,7 @@ func (this mailerUser) GenerateEmailActivateCode(email string) string {
 	return this.user.GenerateEmailActivateCode(email)
 }
 
-func NewMailerUser(u *User) mailer.User {
+func NewMailerUser(u *User) email.User {
 	return mailerUser{u}
 }
 
@@ -65,7 +65,7 @@ func (this mailerRepo) ComposeMetas() map[string]string {
 	return this.repo.ComposeMetas()
 }
 
-func NewMailerRepo(repo *Repository) mailer.Repository {
+func NewMailerRepo(repo *Repository) email.Repository {
 	return mailerRepo{repo}
 }
 
@@ -86,7 +86,7 @@ func (this mailerIssue) HTMLURL() string {
 	return this.issue.HTMLURL()
 }
 
-func NewMailerIssue(issue *Issue) mailer.Issue {
+func NewMailerIssue(issue *Issue) email.Issue {
 	return mailerIssue{issue}
 }
 
@@ -148,7 +148,7 @@ func mailIssueCommentToParticipants(issue *Issue, doer *User, mentions []string)
 			names = append(names, issue.Assignee.Name)
 		}
 	}
-	mailer.SendIssueCommentMail(NewMailerIssue(issue), NewMailerRepo(issue.Repo), NewMailerUser(doer), tos)
+	email.SendIssueCommentMail(NewMailerIssue(issue), NewMailerRepo(issue.Repo), NewMailerUser(doer), tos)
 
 	// Mail mentioned people and exclude watchers.
 	names = append(names, doer.Name)
@@ -160,7 +160,7 @@ func mailIssueCommentToParticipants(issue *Issue, doer *User, mentions []string)
 
 		tos = append(tos, mentions[i])
 	}
-	mailer.SendIssueMentionMail(NewMailerIssue(issue), NewMailerRepo(issue.Repo), NewMailerUser(doer), GetUserEmailsByNames(tos))
+	email.SendIssueMentionMail(NewMailerIssue(issue), NewMailerRepo(issue.Repo), NewMailerUser(doer), GetUserEmailsByNames(tos))
 	return nil
 }
 

+ 2 - 2
internal/mailer/mail.go → internal/email/email.go

@@ -2,7 +2,7 @@
 // Use of this source code is governed by a MIT-style
 // license that can be found in the LICENSE file.
 
-package mailer
+package email
 
 import (
 	"fmt"
@@ -204,7 +204,7 @@ func composeIssueMessage(issue Issue, repo Repository, doer User, tplName string
 	if err != nil {
 		log.Error("HTMLString (%s): %v", tplName, err)
 	}
-	from := gomail.NewMessage().FormatAddress(conf.MailService.FromEmail, doer.DisplayName())
+	from := gomail.NewMessage().FormatAddress(conf.Email.FromEmail, doer.DisplayName())
 	msg := NewMessageFrom(tos, from, subject, content)
 	msg.Info = fmt.Sprintf("Subject: %s, %s", subject, info)
 	return msg

+ 13 - 13
internal/mailer/mailer.go → internal/email/message.go

@@ -2,7 +2,7 @@
 // Use of this source code is governed by a MIT-style
 // license that can be found in the LICENSE file.
 
-package mailer
+package email
 
 import (
 	"crypto/tls"
@@ -34,13 +34,13 @@ func NewMessageFrom(to []string, from, subject, htmlBody string) *Message {
 	msg := gomail.NewMessage()
 	msg.SetHeader("From", from)
 	msg.SetHeader("To", to...)
-	msg.SetHeader("Subject", conf.MailService.SubjectPrefix+subject)
+	msg.SetHeader("Subject", conf.Email.SubjectPrefix+subject)
 	msg.SetDateHeader("Date", time.Now())
 
 	contentType := "text/html"
 	body := htmlBody
 	switchedToPlaintext := false
-	if conf.MailService.UsePlainText || conf.MailService.AddPlainTextAlt {
+	if conf.Email.UsePlainText || conf.Email.AddPlainTextAlt {
 		plainBody, err := html2text.FromString(htmlBody)
 		if err != nil {
 			log.Error("html2text.FromString: %v", err)
@@ -51,7 +51,7 @@ func NewMessageFrom(to []string, from, subject, htmlBody string) *Message {
 		}
 	}
 	msg.SetBody(contentType, body)
-	if switchedToPlaintext && conf.MailService.AddPlainTextAlt && !conf.MailService.UsePlainText {
+	if switchedToPlaintext && conf.Email.AddPlainTextAlt && !conf.Email.UsePlainText {
 		// The AddAlternative method name is confusing - adding html as an "alternative" will actually cause mail
 		// clients to show it as first priority, and the text "main body" is the 2nd priority fallback.
 		// See: https://godoc.org/gopkg.in/gomail.v2#Message.AddAlternative
@@ -65,7 +65,7 @@ func NewMessageFrom(to []string, from, subject, htmlBody string) *Message {
 
 // NewMessage creates new mail message object with default From header.
 func NewMessage(to []string, subject, body string) *Message {
-	return NewMessageFrom(to, conf.MailService.From, subject, body)
+	return NewMessageFrom(to, conf.Email.From, subject, body)
 }
 
 type loginAuth struct {
@@ -99,7 +99,7 @@ type Sender struct {
 }
 
 func (s *Sender) Send(from string, to []string, msg io.WriterTo) error {
-	opts := conf.MailService
+	opts := conf.Email
 
 	host, port, err := net.SplitHostPort(opts.Host)
 	if err != nil {
@@ -137,8 +137,8 @@ func (s *Sender) Send(from string, to []string, msg io.WriterTo) error {
 		return fmt.Errorf("NewClient: %v", err)
 	}
 
-	if !opts.DisableHelo {
-		hostname := opts.HeloHostname
+	if !opts.DisableHELO {
+		hostname := opts.HELOHostname
 		if len(hostname) == 0 {
 			hostname, err = os.Hostname()
 			if err != nil {
@@ -164,12 +164,12 @@ func (s *Sender) Send(from string, to []string, msg io.WriterTo) error {
 		var auth smtp.Auth
 
 		if strings.Contains(options, "CRAM-MD5") {
-			auth = smtp.CRAMMD5Auth(opts.User, opts.Passwd)
+			auth = smtp.CRAMMD5Auth(opts.User, opts.Password)
 		} else if strings.Contains(options, "PLAIN") {
-			auth = smtp.PlainAuth("", opts.User, opts.Passwd, host)
+			auth = smtp.PlainAuth("", opts.User, opts.Password, host)
 		} else if strings.Contains(options, "LOGIN") {
 			// Patch for AUTH LOGIN
-			auth = LoginAuth(opts.User, opts.Passwd)
+			auth = LoginAuth(opts.User, opts.Password)
 		}
 
 		if auth != nil {
@@ -225,11 +225,11 @@ func NewContext() {
 	// Need to check if mailQueue is nil because in during reinstall (user had installed
 	// before but swithed install lock off), this function will be called again
 	// while mail queue is already processing tasks, and produces a race condition.
-	if conf.MailService == nil || mailQueue != nil {
+	if !conf.Email.Enabled || mailQueue != nil {
 		return
 	}
 
-	mailQueue = make(chan *Message, conf.MailService.QueueLength)
+	mailQueue = make(chan *Message, 1000)
 	go processMailQueue()
 }
 

+ 6 - 11
internal/route/admin/admin.go

@@ -17,7 +17,7 @@ import (
 	"gogs.io/gogs/internal/context"
 	"gogs.io/gogs/internal/cron"
 	"gogs.io/gogs/internal/db"
-	"gogs.io/gogs/internal/mailer"
+	"gogs.io/gogs/internal/email"
 	"gogs.io/gogs/internal/process"
 	"gogs.io/gogs/internal/tool"
 )
@@ -180,12 +180,12 @@ func Dashboard(c *context.Context) {
 }
 
 func SendTestMail(c *context.Context) {
-	email := c.Query("email")
+	emailAddr := c.Query("email")
 	// Send a test email to the user's email address and redirect back to Config
-	if err := mailer.SendTestMail(email); err != nil {
-		c.Flash.Error(c.Tr("admin.config.test_mail_failed", email, err))
+	if err := email.SendTestMail(emailAddr); err != nil {
+		c.Flash.Error(c.Tr("admin.config.email.test_mail_failed", emailAddr, err))
 	} else {
-		c.Flash.Info(c.Tr("admin.config.test_mail_sent", email))
+		c.Flash.Info(c.Tr("admin.config.email.test_mail_sent", emailAddr))
 	}
 
 	c.Redirect(conf.Server.Subpath + "/admin/config")
@@ -202,6 +202,7 @@ func Config(c *context.Context) {
 	c.Data["Repository"] = conf.Repository
 	c.Data["Database"] = conf.Database
 	c.Data["Security"] = conf.Security
+	c.Data["Email"] = conf.Email
 
 	c.Data["LogRootPath"] = conf.LogRootPath
 
@@ -210,12 +211,6 @@ func Config(c *context.Context) {
 	c.Data["Service"] = conf.Service
 	c.Data["Webhook"] = conf.Webhook
 
-	c.Data["MailerEnabled"] = false
-	if conf.MailService != nil {
-		c.Data["MailerEnabled"] = true
-		c.Data["Mailer"] = conf.MailService
-	}
-
 	c.Data["CacheAdapter"] = conf.CacheAdapter
 	c.Data["CacheInterval"] = conf.CacheInterval
 	c.Data["CacheConn"] = conf.CacheConn

+ 5 - 5
internal/route/admin/users.go

@@ -13,8 +13,8 @@ import (
 	"gogs.io/gogs/internal/conf"
 	"gogs.io/gogs/internal/context"
 	"gogs.io/gogs/internal/db"
+	"gogs.io/gogs/internal/email"
 	"gogs.io/gogs/internal/form"
-	"gogs.io/gogs/internal/mailer"
 	"gogs.io/gogs/internal/route"
 )
 
@@ -53,7 +53,7 @@ func NewUser(c *context.Context) {
 	}
 	c.Data["Sources"] = sources
 
-	c.Data["CanSendEmail"] = conf.MailService != nil
+	c.Data["CanSendEmail"] = conf.Email.Enabled
 	c.HTML(200, USER_NEW)
 }
 
@@ -69,7 +69,7 @@ func NewUserPost(c *context.Context, f form.AdminCrateUser) {
 	}
 	c.Data["Sources"] = sources
 
-	c.Data["CanSendEmail"] = conf.MailService != nil
+	c.Data["CanSendEmail"] = conf.Email.Enabled
 
 	if c.HasError() {
 		c.HTML(200, USER_NEW)
@@ -115,8 +115,8 @@ func NewUserPost(c *context.Context, f form.AdminCrateUser) {
 	log.Trace("Account created by admin (%s): %s", c.User.Name, u.Name)
 
 	// Send email notification.
-	if f.SendNotify && conf.MailService != nil {
-		mailer.SendRegisterNotifyMail(c.Context, db.NewMailerUser(u))
+	if f.SendNotify && conf.Email.Enabled {
+		email.SendRegisterNotifyMail(c.Context, db.NewMailerUser(u))
 	}
 
 	c.Flash.Success(c.Tr("admin.users.new_success", u.Name))

+ 4 - 4
internal/route/api/v1/admin/user.go

@@ -11,12 +11,12 @@ import (
 
 	api "github.com/gogs/go-gogs-client"
 
+	"gogs.io/gogs/internal/conf"
 	"gogs.io/gogs/internal/context"
 	"gogs.io/gogs/internal/db"
 	"gogs.io/gogs/internal/db/errors"
-	"gogs.io/gogs/internal/mailer"
+	"gogs.io/gogs/internal/email"
 	"gogs.io/gogs/internal/route/api/v1/user"
-	"gogs.io/gogs/internal/conf"
 )
 
 func parseLoginSource(c *context.APIContext, u *db.User, sourceID int64, loginName string) {
@@ -68,8 +68,8 @@ func CreateUser(c *context.APIContext, form api.CreateUserOption) {
 	log.Trace("Account created by admin %q: %s", c.User.Name, u.Name)
 
 	// Send email notification.
-	if form.SendNotify && conf.MailService != nil {
-		mailer.SendRegisterNotifyMail(c.Context.Context, db.NewMailerUser(u))
+	if form.SendNotify && conf.Email.Enabled {
+		email.SendRegisterNotifyMail(c.Context.Context, db.NewMailerUser(u))
 	}
 
 	c.JSON(http.StatusCreated, u.APIFormat())

+ 10 - 6
internal/route/install.go

@@ -24,8 +24,8 @@ import (
 	"gogs.io/gogs/internal/context"
 	"gogs.io/gogs/internal/cron"
 	"gogs.io/gogs/internal/db"
+	"gogs.io/gogs/internal/email"
 	"gogs.io/gogs/internal/form"
-	"gogs.io/gogs/internal/mailer"
 	"gogs.io/gogs/internal/markup"
 	"gogs.io/gogs/internal/osutil"
 	"gogs.io/gogs/internal/ssh"
@@ -63,8 +63,12 @@ func GlobalInit(customConf string) error {
 	log.Trace("Build time: %s", conf.BuildTime)
 	log.Trace("Build commit: %s", conf.BuildCommit)
 
+	if conf.Email.Enabled {
+		log.Trace("Email service is enabled")
+	}
+
 	conf.NewServices()
-	mailer.NewContext()
+	email.NewContext()
 
 	if conf.Security.InstallLock {
 		highlight.NewContext()
@@ -171,10 +175,10 @@ func Install(c *context.Context) {
 	f.LogRootPath = conf.LogRootPath
 
 	// E-mail service settings
-	if conf.MailService != nil {
-		f.SMTPHost = conf.MailService.Host
-		f.SMTPFrom = conf.MailService.From
-		f.SMTPUser = conf.MailService.User
+	if conf.Email.Enabled {
+		f.SMTPHost = conf.Email.Host
+		f.SMTPFrom = conf.Email.From
+		f.SMTPUser = conf.Email.User
 	}
 	f.RegisterConfirm = conf.Service.RegisterEmailConfirm
 	f.MailNotify = conf.Service.EnableNotifyMail

+ 2 - 2
internal/route/repo/setting.go

@@ -19,7 +19,7 @@ import (
 	"gogs.io/gogs/internal/db"
 	"gogs.io/gogs/internal/db/errors"
 	"gogs.io/gogs/internal/form"
-	"gogs.io/gogs/internal/mailer"
+	"gogs.io/gogs/internal/email"
 	"gogs.io/gogs/internal/tool"
 )
 
@@ -399,7 +399,7 @@ func SettingsCollaborationPost(c *context.Context) {
 	}
 
 	if conf.Service.EnableNotifyMail {
-		mailer.SendCollaboratorMail(db.NewMailerUser(u), db.NewMailerUser(c.User), db.NewMailerRepo(c.Repo.Repository))
+		email.SendCollaboratorMail(db.NewMailerUser(u), db.NewMailerUser(c.User), db.NewMailerRepo(c.Repo.Repository))
 	}
 
 	c.Flash.Success(c.Tr("repo.settings.add_collaborator_success"))

+ 9 - 9
internal/route/user/auth.go

@@ -15,8 +15,8 @@ import (
 	"gogs.io/gogs/internal/context"
 	"gogs.io/gogs/internal/db"
 	"gogs.io/gogs/internal/db/errors"
+	"gogs.io/gogs/internal/email"
 	"gogs.io/gogs/internal/form"
-	"gogs.io/gogs/internal/mailer"
 	"gogs.io/gogs/internal/tool"
 )
 
@@ -369,7 +369,7 @@ func SignUpPost(c *context.Context, cpt *captcha.Captcha, f form.Register) {
 
 	// Send confirmation email, no need for social account.
 	if conf.Service.RegisterEmailConfirm && u.ID > 1 {
-		mailer.SendActivateAccountMail(c.Context, db.NewMailerUser(u))
+		email.SendActivateAccountMail(c.Context, db.NewMailerUser(u))
 		c.Data["IsSendRegisterMail"] = true
 		c.Data["Email"] = u.Email
 		c.Data["Hours"] = conf.Service.ActiveCodeLives / 60
@@ -398,7 +398,7 @@ func Activate(c *context.Context) {
 				c.Data["ResendLimited"] = true
 			} else {
 				c.Data["Hours"] = conf.Service.ActiveCodeLives / 60
-				mailer.SendActivateAccountMail(c.Context, db.NewMailerUser(c.User))
+				email.SendActivateAccountMail(c.Context, db.NewMailerUser(c.User))
 
 				if err := c.Cache.Put(c.User.MailResendCacheKey(), 1, 180); err != nil {
 					log.Error("Failed to put cache key 'mail resend': %v", err)
@@ -457,7 +457,7 @@ func ActivateEmail(c *context.Context) {
 func ForgotPasswd(c *context.Context) {
 	c.Title("auth.forgot_password")
 
-	if conf.MailService == nil {
+	if !conf.Email.Enabled {
 		c.Data["IsResetDisable"] = true
 		c.Success(FORGOT_PASSWORD)
 		return
@@ -470,16 +470,16 @@ func ForgotPasswd(c *context.Context) {
 func ForgotPasswdPost(c *context.Context) {
 	c.Title("auth.forgot_password")
 
-	if conf.MailService == nil {
+	if !conf.Email.Enabled {
 		c.Status(403)
 		return
 	}
 	c.Data["IsResetRequest"] = true
 
-	email := c.Query("email")
-	c.Data["Email"] = email
+	emailAddr := c.Query("email")
+	c.Data["Email"] = emailAddr
 
-	u, err := db.GetUserByEmail(email)
+	u, err := db.GetUserByEmail(emailAddr)
 	if err != nil {
 		if errors.IsUserNotExist(err) {
 			c.Data["Hours"] = conf.Service.ActiveCodeLives / 60
@@ -504,7 +504,7 @@ func ForgotPasswdPost(c *context.Context) {
 		return
 	}
 
-	mailer.SendResetPasswordMail(c.Context, db.NewMailerUser(u))
+	email.SendResetPasswordMail(c.Context, db.NewMailerUser(u))
 	if err = c.Cache.Put(u.MailResendCacheKey(), 1, 180); err != nil {
 		log.Error("Failed to put cache key 'mail resend': %v", err)
 	}

+ 5 - 5
internal/route/user/setting.go

@@ -22,8 +22,8 @@ import (
 	"gogs.io/gogs/internal/context"
 	"gogs.io/gogs/internal/db"
 	"gogs.io/gogs/internal/db/errors"
+	"gogs.io/gogs/internal/email"
 	"gogs.io/gogs/internal/form"
-	"gogs.io/gogs/internal/mailer"
 	"gogs.io/gogs/internal/tool"
 )
 
@@ -259,12 +259,12 @@ func SettingsEmailPost(c *context.Context, f form.AddEmail) {
 		return
 	}
 
-	email := &db.EmailAddress{
+	emailAddr := &db.EmailAddress{
 		UID:         c.User.ID,
 		Email:       f.Email,
 		IsActivated: !conf.Service.RegisterEmailConfirm,
 	}
-	if err := db.AddEmailAddress(email); err != nil {
+	if err := db.AddEmailAddress(emailAddr); err != nil {
 		if db.IsErrEmailAlreadyUsed(err) {
 			c.RenderWithErr(c.Tr("form.email_been_used"), SETTINGS_EMAILS, &f)
 		} else {
@@ -275,12 +275,12 @@ func SettingsEmailPost(c *context.Context, f form.AddEmail) {
 
 	// Send confirmation email
 	if conf.Service.RegisterEmailConfirm {
-		mailer.SendActivateEmailMail(c.Context, db.NewMailerUser(c.User), email.Email)
+		email.SendActivateEmailMail(c.Context, db.NewMailerUser(c.User), emailAddr.Email)
 
 		if err := c.Cache.Put("MailResendLimit_"+c.User.LowerName, c.User.LowerName, 180); err != nil {
 			log.Error("Set cache 'MailResendLimit' failed: %v", err)
 		}
-		c.Flash.Info(c.Tr("settings.add_email_confirmation_sent", email.Email, conf.Service.ActiveCodeLives/60))
+		c.Flash.Info(c.Tr("settings.add_email_confirmation_sent", emailAddr.Email, conf.Service.ActiveCodeLives/60))
 	} else {
 		c.Flash.Success(c.Tr("settings.add_email_success"))
 	}

+ 58 - 29
templates/admin/config.tmpl

@@ -203,6 +203,64 @@
 					</dl>
 				</div>
 
+				{{/* Email settings */}}
+				<h4 class="ui top attached header">
+					{{.i18n.Tr "admin.config.email_config"}}
+				</h4>
+				<div class="ui attached table segment">
+					<dl class="dl-horizontal admin-dl-horizontal">
+						<dt>{{.i18n.Tr "admin.config.email.enabled"}}</dt>
+						<dd><i class="fa fa{{if .Email.Enabled}}-check{{end}}-square-o"></i></dd>
+						{{if .Email.Enabled}}
+							<dt>{{.i18n.Tr "admin.config.email.subject_prefix"}}</dt>
+							<dd><code>{{.Email.SubjectPrefix}}</code></dd>
+							<dt>{{.i18n.Tr "admin.config.email.host"}}</dt>
+							<dd>{{.Email.Host}}</dd>
+							<dt>{{.i18n.Tr "admin.config.email.from"}}</dt>
+							<dd>{{.Email.From}}</dd>
+							<dt>{{.i18n.Tr "admin.config.email.user"}}</dt>
+							<dd>{{.Email.User}}</dd>
+
+							<div class="ui divider"></div>
+
+							<dt>{{.i18n.Tr "admin.config.email.disable_helo"}}</dt>
+							<dd><i class="fa fa{{if .Email.DisableHELO}}-check{{end}}-square-o"></i></dd>
+							<dt>{{.i18n.Tr "admin.config.email.helo_hostname"}}</dt>
+							<dd>{{if .Email.HELOHostname}}{{.Email.HELOHostname}}{{else}}{{.i18n.Tr "admin.config.not_set"}}{{end}}</dd>
+
+							<div class="ui divider"></div>
+
+							<dt>{{.i18n.Tr "admin.config.email.skip_verify"}}</dt>
+							<dd><i class="fa fa{{if .Email.SkipVerify}}-check{{end}}-square-o"></i></dd>
+							<dt>{{.i18n.Tr "admin.config.email.use_certificate"}}</dt>
+							<dd><i class="fa fa{{if .Email.UseCertificate}}-check{{end}}-square-o"></i></dd>
+							<dt>{{.i18n.Tr "admin.config.email.cert_file"}}</dt>
+							<dd><code>{{.Email.CertFile}}</code></dd>
+							<dt>{{.i18n.Tr "admin.config.email.key_file"}}</dt>
+							<dd><code>{{.Email.KeyFile}}</code></dd>
+
+							<div class="ui divider"></div>
+
+							<dt>{{.i18n.Tr "admin.config.email.use_plain_text"}}</dt>
+							<dd><i class="fa fa{{if .Email.UsePlainText}}-check{{end}}-square-o"></i></dd>
+							<dt>{{.i18n.Tr "admin.config.email.add_plain_text_alt"}}</dt>
+							<dd><i class="fa fa{{if .Email.AddPlainTextAlt}}-check{{end}}-square-o"></i></dd>
+
+							<div class="ui divider"></div>
+
+							<form class="ui form" action="{{AppSubURL}}/admin/config/test_mail" method="post">
+								{{.CSRFTokenHTML}}
+								<div class="inline field ui left">
+									<div class="ui input">
+										<input type="email" name="email" required>
+									</div>
+								</div>
+								<button class="ui green button" id="test-mail-btn">{{.i18n.Tr "admin.config.email.send_test_mail"}}</button>
+							</form>
+						{{end}}
+					</dl>
+				</div>
+
 				<!-- HTTP Configuration -->
 				<h4 class="ui top attached header">
 					{{.i18n.Tr "admin.config.http_config"}}
@@ -261,35 +319,6 @@
 					</dl>
 				</div>
 
-				<h4 class="ui top attached header">
-					{{.i18n.Tr "admin.config.mailer_config"}}
-				</h4>
-				<div class="ui attached table segment">
-					<dl class="dl-horizontal admin-dl-horizontal">
-						<dt>{{.i18n.Tr "admin.config.mailer_enabled"}}</dt>
-						<dd><i class="fa fa{{if .MailerEnabled}}-check{{end}}-square-o"></i></dd>
-						{{if .MailerEnabled}}
-							<dt>{{.i18n.Tr "admin.config.mailer_subject_prefix"}}</dt>
-							<dd><code>{{.Mailer.SubjectPrefix}}</code></dd>
-							<dt>{{.i18n.Tr "admin.config.mailer_disable_helo"}}</dt>
-							<dd><i class="fa fa{{if .Mailer.DisableHelo}}-check{{end}}-square-o"></i></dd>
-							<dt>{{.i18n.Tr "admin.config.mailer_host"}}</dt>
-							<dd>{{.Mailer.Host}}</dd>
-							<dt>{{.i18n.Tr "admin.config.mailer_user"}}</dt>
-							<dd>{{if .Mailer.User}}{{.Mailer.User}}{{else}}(empty){{end}}</dd><br>
-							<form class="ui form" action="{{AppSubURL}}/admin/config/test_mail" method="post">
-								{{.CSRFTokenHTML}}
-								<div class="inline field ui left">
-									<div class="ui input">
-										<input type="email" name="email" required>
-									</div>
-								</div>
-								<button class="ui green button" id="test-mail-btn">{{.i18n.Tr "admin.config.send_test_mail"}}</button>
-							</form>
-						{{end}}
-					</dl>
-				</div>
-
 				<h4 class="ui top attached header">
 					{{.i18n.Tr "admin.config.cache_config"}}
 				</h4>

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff