2020-02-07 17:27:45 +01:00
|
|
|
// Vikunja is a to-do list application to facilitate your life.
|
2020-01-09 18:33:22 +01:00
|
|
|
// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
|
2018-11-26 21:17:33 +01:00
|
|
|
//
|
2019-12-04 20:39:56 +01:00
|
|
|
// This program is free software: you can redistribute it and/or modify
|
2020-12-23 16:41:52 +01:00
|
|
|
// it under the terms of the GNU Affero General Public Licensee as published by
|
2019-12-04 20:39:56 +01:00
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
2018-11-26 21:17:33 +01:00
|
|
|
//
|
2019-12-04 20:39:56 +01:00
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2020-12-23 16:41:52 +01:00
|
|
|
// GNU Affero General Public Licensee for more details.
|
2018-11-26 21:17:33 +01:00
|
|
|
//
|
2020-12-23 16:41:52 +01:00
|
|
|
// You should have received a copy of the GNU Affero General Public Licensee
|
2019-12-04 20:39:56 +01:00
|
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2018-11-26 21:17:33 +01:00
|
|
|
|
2018-10-27 11:33:28 +02:00
|
|
|
package mail
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2020-10-11 22:10:03 +02:00
|
|
|
"html/template"
|
|
|
|
|
2019-07-06 22:12:26 +02:00
|
|
|
"code.vikunja.io/api/pkg/config"
|
2019-07-11 21:10:42 +02:00
|
|
|
"code.vikunja.io/api/pkg/log"
|
|
|
|
"code.vikunja.io/api/pkg/static"
|
2018-10-31 13:42:38 +01:00
|
|
|
"code.vikunja.io/api/pkg/utils"
|
2019-07-11 21:10:42 +02:00
|
|
|
"github.com/shurcooL/httpfs/html/vfstemplate"
|
2018-10-27 11:33:28 +02:00
|
|
|
"gopkg.in/gomail.v2"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Opts holds infos for a mail
|
|
|
|
type Opts struct {
|
|
|
|
To string
|
|
|
|
Subject string
|
|
|
|
Message string
|
|
|
|
HTMLMessage string
|
|
|
|
ContentType ContentType
|
|
|
|
Boundary string
|
|
|
|
Headers []*header
|
|
|
|
}
|
|
|
|
|
|
|
|
// ContentType represents mail content types
|
|
|
|
type ContentType int
|
|
|
|
|
|
|
|
// Enumerate all the team rights
|
|
|
|
const (
|
|
|
|
ContentTypePlain ContentType = iota
|
|
|
|
ContentTypeHTML
|
|
|
|
ContentTypeMultipart
|
|
|
|
)
|
|
|
|
|
|
|
|
type header struct {
|
|
|
|
Field string
|
|
|
|
Content string
|
|
|
|
}
|
|
|
|
|
2020-05-29 15:10:06 +02:00
|
|
|
// SendTestMail sends a test mail to a receipient.
|
|
|
|
// It works without a queue.
|
|
|
|
func SendTestMail(to string) error {
|
|
|
|
if config.MailerHost.GetString() == "" {
|
|
|
|
log.Warning("Mailer seems to be not configured! Please see the config docs for more details.")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
d := getDialer()
|
|
|
|
s, err := d.Dial()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer s.Close()
|
|
|
|
|
|
|
|
m := gomail.NewMessage()
|
|
|
|
m.SetHeader("From", config.MailerFromEmail.GetString())
|
|
|
|
m.SetHeader("To", to)
|
|
|
|
m.SetHeader("Subject", "Test from Vikunja")
|
|
|
|
m.SetBody("text/plain", "This is a test mail! If you got this, Vikunja is correctly set up to send emails.")
|
|
|
|
|
|
|
|
return gomail.Send(s, m)
|
|
|
|
}
|
|
|
|
|
2018-10-27 11:33:28 +02:00
|
|
|
// SendMail puts a mail in the queue
|
|
|
|
func SendMail(opts *Opts) {
|
|
|
|
m := gomail.NewMessage()
|
2019-07-06 22:12:26 +02:00
|
|
|
m.SetHeader("From", config.MailerFromEmail.GetString())
|
2018-10-27 11:33:28 +02:00
|
|
|
m.SetHeader("To", opts.To)
|
|
|
|
m.SetHeader("Subject", opts.Subject)
|
|
|
|
for _, h := range opts.Headers {
|
|
|
|
m.SetHeader(h.Field, h.Content)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch opts.ContentType {
|
|
|
|
case ContentTypePlain:
|
|
|
|
m.SetBody("text/plain", opts.Message)
|
|
|
|
case ContentTypeHTML:
|
|
|
|
m.SetBody("text/html", opts.Message)
|
|
|
|
case ContentTypeMultipart:
|
|
|
|
m.SetBody("text/plain", opts.Message)
|
|
|
|
m.AddAlternative("text/html", opts.HTMLMessage)
|
|
|
|
}
|
|
|
|
|
|
|
|
Queue <- m
|
|
|
|
}
|
|
|
|
|
|
|
|
// Template holds a pointer about a template
|
|
|
|
type Template struct {
|
|
|
|
Templates *template.Template
|
|
|
|
}
|
|
|
|
|
|
|
|
// SendMailWithTemplate parses a template and sends it via mail
|
|
|
|
func SendMailWithTemplate(to, subject, tpl string, data map[string]interface{}) {
|
|
|
|
var htmlContent bytes.Buffer
|
|
|
|
var plainContent bytes.Buffer
|
|
|
|
|
2019-07-11 21:10:42 +02:00
|
|
|
t, err := vfstemplate.ParseGlob(static.Templates, nil, "*.tmpl")
|
|
|
|
if err != nil {
|
2019-07-20 20:12:10 +02:00
|
|
|
log.Errorf("SendMailWithTemplate: ParseGlob: %v", err)
|
2019-07-11 21:10:42 +02:00
|
|
|
return
|
2018-10-27 11:33:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
boundary := "np" + utils.MakeRandomString(13)
|
|
|
|
|
|
|
|
data["Boundary"] = boundary
|
2019-07-06 22:12:26 +02:00
|
|
|
data["FrontendURL"] = config.ServiceFrontendurl.GetString()
|
2018-10-27 11:33:28 +02:00
|
|
|
|
2019-07-11 21:10:42 +02:00
|
|
|
if err := t.ExecuteTemplate(&htmlContent, tpl+".html.tmpl", data); err != nil {
|
2019-07-20 20:12:10 +02:00
|
|
|
log.Errorf("ExecuteTemplate: %v", err)
|
2018-10-27 11:33:28 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-07-11 21:10:42 +02:00
|
|
|
if err := t.ExecuteTemplate(&plainContent, tpl+".plain.tmpl", data); err != nil {
|
2019-07-20 20:12:10 +02:00
|
|
|
log.Errorf("ExecuteTemplate: %v", err)
|
2018-10-27 11:33:28 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
opts := &Opts{
|
|
|
|
To: to,
|
|
|
|
Subject: subject,
|
|
|
|
Message: plainContent.String(),
|
|
|
|
HTMLMessage: htmlContent.String(),
|
|
|
|
ContentType: ContentTypeMultipart,
|
|
|
|
Boundary: boundary,
|
|
|
|
}
|
|
|
|
|
|
|
|
SendMail(opts)
|
|
|
|
}
|