summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/auth/user_form.go8
-rw-r--r--modules/mailer/mail.go37
-rw-r--r--modules/mailer/mailer.go71
-rw-r--r--modules/setting/setting.go10
4 files changed, 99 insertions, 27 deletions
diff --git a/modules/auth/user_form.go b/modules/auth/user_form.go
index 4dfe2499f1..becd5cbca8 100644
--- a/modules/auth/user_form.go
+++ b/modules/auth/user_form.go
@@ -97,6 +97,14 @@ func (f *UploadAvatarForm) Validate(ctx *macaron.Context, errs binding.Errors) b
return validate(errs, ctx.Data, f, ctx.Locale)
}
+type AddEmailForm struct {
+ Email string `form:"email" binding:"Required;Email;MaxSize(50)"`
+}
+
+func (f *AddEmailForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
+ return validate(errs, ctx.Data, f, ctx.Locale)
+}
+
type ChangePasswordForm struct {
OldPassword string `form:"old_password" binding:"Required;MinSize(6);MaxSize(255)"`
Password string `form:"password" binding:"Required;MinSize(6);MaxSize(255)"`
diff --git a/modules/mailer/mail.go b/modules/mailer/mail.go
index 6c73e7e58f..ae8ce6531a 100644
--- a/modules/mailer/mail.go
+++ b/modules/mailer/mail.go
@@ -21,6 +21,7 @@ import (
const (
AUTH_ACTIVE base.TplName = "mail/auth/active"
+ AUTH_ACTIVATE_EMAIL base.TplName = "mail/auth/activate_email"
AUTH_REGISTER_SUCCESS base.TplName = "mail/auth/register_success"
AUTH_RESET_PASSWORD base.TplName = "mail/auth/reset_passwd"
@@ -30,9 +31,7 @@ const (
// Create New mail message use MailFrom and MailUser
func NewMailMessageFrom(To []string, from, subject, body string) Message {
- msg := NewHtmlMessage(To, from, subject, body)
- msg.User = setting.MailService.User
- return msg
+ return NewHtmlMessage(To, from, subject, body)
}
// Create New mail message use MailFrom and MailUser
@@ -64,6 +63,17 @@ func CreateUserActiveCode(u *models.User, startInf interface{}) string {
return code
}
+// create a time limit code for user active
+func CreateUserEmailActivateCode(u *models.User, e *models.EmailAddress, startInf interface{}) string {
+ minutes := setting.Service.ActiveCodeLives
+ data := com.ToStr(u.Id) + e.Email + u.LowerName + u.Passwd + u.Rands
+ code := base.CreateTimeLimitCode(data, minutes, startInf)
+
+ // add tail hex username
+ code += hex.EncodeToString([]byte(u.LowerName))
+ return code
+}
+
// Send user register mail with active code
func SendRegisterMail(r macaron.Render, u *models.User) {
code := CreateUserActiveCode(u, nil)
@@ -103,6 +113,27 @@ func SendActiveMail(r macaron.Render, u *models.User) {
SendAsync(&msg)
}
+// Send email to verify secondary email.
+func SendActivateEmail(r macaron.Render, user *models.User, email *models.EmailAddress) {
+ code := CreateUserEmailActivateCode(user, email, nil)
+
+ subject := "Verify your e-mail address"
+
+ data := GetMailTmplData(user)
+ data["Code"] = code
+ data["Email"] = email.Email
+ body, err := r.HTMLString(string(AUTH_ACTIVATE_EMAIL), data)
+ if err != nil {
+ log.Error(4, "mail.SendActiveMail(fail to render): %v", err)
+ return
+ }
+
+ msg := NewMailMessage([]string{email.Email}, subject, body)
+ msg.Info = fmt.Sprintf("UID: %d, send activate email to %s", user.Id, email.Email)
+
+ SendAsync(&msg)
+}
+
// Send reset password email.
func SendResetPasswdMail(r macaron.Render, u *models.User) {
code := CreateUserActiveCode(u, nil)
diff --git a/modules/mailer/mailer.go b/modules/mailer/mailer.go
index 474e1481cd..e2d185d82d 100644
--- a/modules/mailer/mailer.go
+++ b/modules/mailer/mailer.go
@@ -8,6 +8,7 @@ import (
"crypto/tls"
"fmt"
"net"
+ "net/mail"
"net/smtp"
"strings"
@@ -20,7 +21,6 @@ type Message struct {
From string
Subject string
Body string
- User string
Type string
Massive bool
Info string
@@ -35,8 +35,7 @@ func (m Message) Content() string {
}
// create mail content
- content := "From: \"" + m.From + "\" <" + m.User +
- ">\r\nSubject: " + m.Subject + "\r\nContent-Type: " + contentType + "\r\n\r\n" + m.Body
+ content := "From: " + m.From + "\r\nSubject: " + m.Subject + "\r\nContent-Type: " + contentType + "\r\n\r\n" + m.Body
return content
}
@@ -67,29 +66,67 @@ func processMailQueue() {
}
// sendMail allows mail with self-signed certificates.
-func sendMail(hostAddressWithPort string, auth smtp.Auth, from string, recipients []string, msgContent []byte) error {
- client, err := smtp.Dial(hostAddressWithPort)
+func sendMail(settings *setting.Mailer, recipients []string, msgContent []byte) error {
+ host, port, err := net.SplitHostPort(settings.Host)
if err != nil {
return err
}
- host, _, _ := net.SplitHostPort(hostAddressWithPort)
- tlsConn := &tls.Config{
- InsecureSkipVerify: true,
+ tlsconfig := &tls.Config{
+ InsecureSkipVerify: settings.SkipVerify,
ServerName: host,
}
- if err = client.StartTLS(tlsConn); err != nil {
+
+ conn, err := net.Dial("tcp", net.JoinHostPort(host, port))
+ if err != nil {
return err
}
+ defer conn.Close()
+
+ isSecureConn := false
+ // Start TLS directly if the port ends with 465 (SMTPS protocol)
+ if strings.HasSuffix(port, "465") {
+ conn = tls.Client(conn, tlsconfig)
+ isSecureConn = true
+ }
- if ok, _ := client.Extension("AUTH"); ok && auth != nil {
- if err = client.Auth(auth); err != nil {
+ client, err := smtp.NewClient(conn, host)
+ if err != nil {
+ return err
+ }
+
+ // If not using SMTPS, alway use STARTTLS if available
+ hasStartTLS, _ := client.Extension("STARTTLS")
+ if !isSecureConn && hasStartTLS {
+ if err = client.StartTLS(tlsconfig); err != nil {
return err
}
}
- if err = client.Mail(from); err != nil {
+ canAuth, options := client.Extension("AUTH")
+
+ if canAuth && len(settings.User) > 0 {
+ var auth smtp.Auth
+
+ if strings.Contains(options, "CRAM-MD5") {
+ auth = smtp.CRAMMD5Auth(settings.User, settings.Passwd)
+ } else if strings.Contains(options, "PLAIN") {
+ auth = smtp.PlainAuth("", settings.User, settings.Passwd, host)
+ }
+
+ if auth != nil {
+ if err = client.Auth(auth); err != nil {
+ return err
+ }
+ }
+ }
+
+ if fromAddress, err := mail.ParseAddress(settings.From); err != nil {
return err
+ } else {
+ if err = client.Mail(fromAddress.Address); err != nil {
+ return err
+ }
}
for _, rec := range recipients {
@@ -116,7 +153,6 @@ func sendMail(hostAddressWithPort string, auth smtp.Auth, from string, recipient
// Direct Send mail message
func Send(msg *Message) (int, error) {
log.Trace("Sending mails to: %s", strings.Join(msg.To, "; "))
- host := strings.Split(setting.MailService.Host, ":")
// get message body
content := msg.Content()
@@ -127,17 +163,12 @@ func Send(msg *Message) (int, error) {
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 {
// send mail to multiple emails one by one
num := 0
for _, to := range msg.To {
body := []byte("To: " + to + "\r\n" + content)
- err := sendMail(setting.MailService.Host, auth, msg.From, []string{to}, body)
+ err := sendMail(setting.MailService, []string{to}, body)
if err != nil {
return num, err
}
@@ -148,7 +179,7 @@ func Send(msg *Message) (int, error) {
body := []byte("To: " + strings.Join(msg.To, ";") + "\r\n" + content)
// send to multiple emails in one message
- err := sendMail(setting.MailService.Host, auth, msg.From, msg.To, body)
+ err := sendMail(setting.MailService, msg.To, body)
if err != nil {
return 0, err
} else {
diff --git a/modules/setting/setting.go b/modules/setting/setting.go
index 7765a859ab..76e1ab7696 100644
--- a/modules/setting/setting.go
+++ b/modules/setting/setting.go
@@ -437,6 +437,7 @@ type Mailer struct {
Host string
From string
User, Passwd string
+ SkipVerify bool
}
type OauthInfo struct {
@@ -463,10 +464,11 @@ func newMailService() {
}
MailService = &Mailer{
- Name: Cfg.MustValue("mailer", "NAME", AppName),
- Host: Cfg.MustValue("mailer", "HOST"),
- User: Cfg.MustValue("mailer", "USER"),
- Passwd: Cfg.MustValue("mailer", "PASSWD"),
+ Name: Cfg.MustValue("mailer", "NAME", AppName),
+ Host: Cfg.MustValue("mailer", "HOST"),
+ User: Cfg.MustValue("mailer", "USER"),
+ Passwd: Cfg.MustValue("mailer", "PASSWD"),
+ SkipVerify: Cfg.MustBool("mailer", "SKIP_VERIFY", false),
}
MailService.From = Cfg.MustValue("mailer", "FROM", MailService.User)
log.Info("Mail Service Enabled")