summaryrefslogtreecommitdiff
path: root/internal/email/common.go
diff options
context:
space:
mode:
authorLibravatar tobi <31960611+tsmethurst@users.noreply.github.com>2023-03-19 13:11:46 +0100
committerLibravatar GitHub <noreply@github.com>2023-03-19 13:11:46 +0100
commit7db81cde444f6bc95e79527af0997de1788d48c7 (patch)
treef6c077ec298a4f018d0870798bc46bd64ba70069 /internal/email/common.go
parent[docs] Update docs on how to login (#1626) (diff)
downloadgotosocial-7db81cde444f6bc95e79527af0997de1788d48c7.tar.xz
[feature] Email notifications for new / closed moderation reports (#1628)
* start fiddling about with email sending to allow multiple recipients * do some fiddling * notifs working * notify on closed report * finishing up * envparsing * use strings.ContainsAny
Diffstat (limited to 'internal/email/common.go')
-rw-r--r--internal/email/common.go112
1 files changed, 112 insertions, 0 deletions
diff --git a/internal/email/common.go b/internal/email/common.go
new file mode 100644
index 000000000..ab4176895
--- /dev/null
+++ b/internal/email/common.go
@@ -0,0 +1,112 @@
+// GoToSocial
+// Copyright (C) GoToSocial Authors admin@gotosocial.org
+// SPDX-License-Identifier: AGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// 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
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package email
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "net/smtp"
+ "os"
+ "path/filepath"
+ "strings"
+ "text/template"
+
+ "github.com/superseriousbusiness/gotosocial/internal/config"
+ "github.com/superseriousbusiness/gotosocial/internal/gtserror"
+)
+
+func (s *sender) sendTemplate(template string, subject string, data any, toAddresses ...string) error {
+ buf := &bytes.Buffer{}
+ if err := s.template.ExecuteTemplate(buf, template, data); err != nil {
+ return err
+ }
+
+ msg, err := assembleMessage(subject, buf.String(), s.from, toAddresses...)
+ if err != nil {
+ return err
+ }
+
+ if err := smtp.SendMail(s.hostAddress, s.auth, s.from, toAddresses, msg); err != nil {
+ return gtserror.SetType(err, gtserror.TypeSMTP)
+ }
+
+ return nil
+}
+
+func loadTemplates(templateBaseDir string) (*template.Template, error) {
+ if !filepath.IsAbs(templateBaseDir) {
+ cwd, err := os.Getwd()
+ if err != nil {
+ return nil, fmt.Errorf("error getting current working directory: %s", err)
+ }
+ templateBaseDir = filepath.Join(cwd, templateBaseDir)
+ }
+
+ // look for all templates that start with 'email_'
+ return template.ParseGlob(filepath.Join(templateBaseDir, "email_*"))
+}
+
+// assembleMessage assembles a valid email message following:
+// - https://datatracker.ietf.org/doc/html/rfc2822
+// - https://pkg.go.dev/net/smtp#SendMail
+func assembleMessage(mailSubject string, mailBody string, mailFrom string, mailTo ...string) ([]byte, error) {
+ if strings.ContainsAny(mailSubject, "\r\n") {
+ return nil, errors.New("email subject must not contain newline characters")
+ }
+
+ if strings.ContainsAny(mailFrom, "\r\n") {
+ return nil, errors.New("email from address must not contain newline characters")
+ }
+
+ for _, to := range mailTo {
+ if strings.ContainsAny(to, "\r\n") {
+ return nil, errors.New("email to address must not contain newline characters")
+ }
+ }
+
+ // Normalize the message body to use CRLF line endings
+ const CRLF = "\r\n"
+ mailBody = strings.ReplaceAll(mailBody, CRLF, "\n")
+ mailBody = strings.ReplaceAll(mailBody, "\n", CRLF)
+
+ msg := bytes.Buffer{}
+ switch {
+ case len(mailTo) == 1:
+ // Address email directly to the one recipient.
+ msg.WriteString("To: " + mailTo[0] + CRLF)
+ case config.GetSMTPDiscloseRecipients():
+ // Simply address To all recipients.
+ msg.WriteString("To: " + strings.Join(mailTo, ", ") + CRLF)
+ default:
+ // Address To anonymous group.
+ //
+ // Email will be sent to all recipients but we shouldn't include Bcc header.
+ //
+ // From the smtp.SendMail function: 'Sending "Bcc" messages is accomplished by
+ // including an email address in the to parameter but not including it in the
+ // msg headers.'
+ msg.WriteString("To: Undisclosed Recipients:;" + CRLF)
+ }
+ msg.WriteString("Subject: " + mailSubject + CRLF)
+ msg.WriteString(CRLF)
+ msg.WriteString(mailBody)
+ msg.WriteString(CRLF)
+
+ return msg.Bytes(), nil
+}