2020-02-07 16:27:45 +00:00
|
|
|
// Vikunja is a to-do list application to facilitate your life.
|
2023-09-01 06:32:28 +00:00
|
|
|
// Copyright 2018-present Vikunja and contributors. All rights reserved.
|
2018-11-26 20:17:33 +00:00
|
|
|
//
|
2019-12-04 19:39:56 +00:00
|
|
|
// This program is free software: you can redistribute it and/or modify
|
2020-12-23 15:41:52 +00:00
|
|
|
// it under the terms of the GNU Affero General Public Licensee as published by
|
2019-12-04 19:39:56 +00:00
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
2018-11-26 20:17:33 +00:00
|
|
|
//
|
2019-12-04 19:39:56 +00: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 15:41:52 +00:00
|
|
|
// GNU Affero General Public Licensee for more details.
|
2018-11-26 20:17:33 +00:00
|
|
|
//
|
2020-12-23 15:41:52 +00:00
|
|
|
// You should have received a copy of the GNU Affero General Public Licensee
|
2019-12-04 19:39:56 +00:00
|
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2018-11-26 20:17:33 +00:00
|
|
|
|
2018-10-27 09:33:28 +00:00
|
|
|
package mail
|
|
|
|
|
|
|
|
import (
|
2022-07-07 13:54:38 +00:00
|
|
|
"embed"
|
2022-06-19 14:26:17 +00:00
|
|
|
"io"
|
|
|
|
|
2019-07-06 20:12:26 +00:00
|
|
|
"code.vikunja.io/api/pkg/config"
|
2019-07-11 19:10:42 +00:00
|
|
|
"code.vikunja.io/api/pkg/log"
|
2022-06-19 13:57:00 +00:00
|
|
|
"code.vikunja.io/api/pkg/version"
|
|
|
|
|
|
|
|
"github.com/wneessen/go-mail"
|
2018-10-27 09:33:28 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Opts holds infos for a mail
|
|
|
|
type Opts struct {
|
2021-02-07 21:05:09 +00:00
|
|
|
From string
|
2018-10-27 09:33:28 +00:00
|
|
|
To string
|
|
|
|
Subject string
|
|
|
|
Message string
|
|
|
|
HTMLMessage string
|
|
|
|
ContentType ContentType
|
|
|
|
Boundary string
|
|
|
|
Headers []*header
|
2022-06-19 14:21:11 +00:00
|
|
|
Embeds map[string]io.Reader
|
2022-07-07 13:54:38 +00:00
|
|
|
EmbedFS map[string]*embed.FS
|
2018-10-27 09:33:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ContentType represents mail content types
|
|
|
|
type ContentType int
|
|
|
|
|
|
|
|
// Enumerate all the team rights
|
|
|
|
const (
|
|
|
|
ContentTypePlain ContentType = iota
|
|
|
|
ContentTypeHTML
|
|
|
|
ContentTypeMultipart
|
|
|
|
)
|
|
|
|
|
|
|
|
type header struct {
|
2022-06-19 13:57:00 +00:00
|
|
|
Field mail.Header
|
2018-10-27 09:33:28 +00:00
|
|
|
Content string
|
|
|
|
}
|
|
|
|
|
2022-06-19 13:57:00 +00:00
|
|
|
// SendTestMail sends a test mail to a recipient.
|
2020-05-29 13:10:06 +00:00
|
|
|
// It works without a queue.
|
2021-02-07 21:05:09 +00:00
|
|
|
func SendTestMail(opts *Opts) error {
|
2020-05-29 13:10:06 +00:00
|
|
|
if config.MailerHost.GetString() == "" {
|
|
|
|
log.Warning("Mailer seems to be not configured! Please see the config docs for more details.")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-06-19 13:57:00 +00:00
|
|
|
c, err := getClient()
|
2020-05-29 13:10:06 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-06-19 13:57:00 +00:00
|
|
|
m := getMessage(opts)
|
2020-05-29 13:10:06 +00:00
|
|
|
|
2022-06-19 13:57:00 +00:00
|
|
|
return c.DialAndSend(m)
|
2020-05-29 13:10:06 +00:00
|
|
|
}
|
|
|
|
|
2022-06-19 13:57:00 +00:00
|
|
|
func getMessage(opts *Opts) *mail.Msg {
|
|
|
|
m := mail.NewMsg()
|
|
|
|
m.SetUserAgent("Vikunja " + version.Version)
|
2021-02-07 21:05:09 +00:00
|
|
|
if opts.From == "" {
|
2021-07-29 15:42:49 +00:00
|
|
|
opts.From = "Vikunja <" + config.MailerFromEmail.GetString() + ">"
|
2021-02-07 21:05:09 +00:00
|
|
|
}
|
2022-06-19 13:57:00 +00:00
|
|
|
_ = m.From(opts.From)
|
|
|
|
_ = m.To(opts.To)
|
|
|
|
m.Subject(opts.Subject)
|
2022-06-19 14:21:11 +00:00
|
|
|
|
2018-10-27 09:33:28 +00:00
|
|
|
for _, h := range opts.Headers {
|
2022-11-21 11:56:19 +00:00
|
|
|
m.SetGenHeader(h.Field, h.Content)
|
2018-10-27 09:33:28 +00:00
|
|
|
}
|
|
|
|
|
2022-06-19 14:21:11 +00:00
|
|
|
for name, content := range opts.Embeds {
|
2024-06-18 11:28:10 +00:00
|
|
|
err := m.EmbedReader(name, content)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("Could not create reader to embet into mail: %s", err)
|
|
|
|
}
|
2022-06-19 14:21:11 +00:00
|
|
|
}
|
|
|
|
|
2022-07-07 13:54:38 +00:00
|
|
|
for name, fs := range opts.EmbedFS {
|
|
|
|
err := m.EmbedFromEmbedFS(name, fs)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("Error embedding %s via embed.FS into mail: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-27 09:33:28 +00:00
|
|
|
switch opts.ContentType {
|
|
|
|
case ContentTypePlain:
|
2022-06-19 13:57:00 +00:00
|
|
|
m.SetBodyString("text/plain", opts.Message)
|
2018-10-27 09:33:28 +00:00
|
|
|
case ContentTypeHTML:
|
2022-06-19 13:57:00 +00:00
|
|
|
m.SetBodyString("text/html", opts.Message)
|
2018-10-27 09:33:28 +00:00
|
|
|
case ContentTypeMultipart:
|
2022-06-19 13:57:00 +00:00
|
|
|
m.SetBodyString("text/plain", opts.Message)
|
|
|
|
m.AddAlternativeString("text/html", opts.HTMLMessage)
|
2018-10-27 09:33:28 +00:00
|
|
|
}
|
2022-06-19 13:57:00 +00:00
|
|
|
|
2021-02-07 21:05:09 +00:00
|
|
|
return m
|
2018-10-27 09:33:28 +00:00
|
|
|
}
|
|
|
|
|
2021-02-07 21:05:09 +00:00
|
|
|
// SendMail puts a mail in the queue
|
|
|
|
func SendMail(opts *Opts) {
|
|
|
|
if isUnderTest {
|
|
|
|
sentMails = append(sentMails, opts)
|
2018-10-27 09:33:28 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-06-19 13:57:00 +00:00
|
|
|
m := getMessage(opts)
|
2021-02-07 21:05:09 +00:00
|
|
|
Queue <- m
|
2018-10-27 09:33:28 +00:00
|
|
|
}
|