mirror of
https://github.com/gogs/gogs.git
synced 2025-12-20 23:30:00 +01:00
conf: overhaul email settings (#5940)
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
7
Makefile
7
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 ./...
|
||||
|
||||
65
conf/app.ini
65
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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -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/")
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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 = ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,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
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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"))
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user