[feature] Allow admins to send test emails (#1620)

* [feature] Allow admins to send test emails

* implement unwrap on new error type

* add + use gtserror types

* GoToSocial Email Test -> GoToSocial Test Email

* add + use getInstance db call

* removed unused "unknown" error type
This commit is contained in:
tobi
2023-03-14 17:11:04 +01:00
committed by GitHub
parent d5529d6c9f
commit 196cd88b1c
17 changed files with 460 additions and 83 deletions

View File

@@ -21,8 +21,7 @@ import (
"bytes"
"net/smtp"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/log"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
)
const (
@@ -30,21 +29,6 @@ const (
confirmSubject = "GoToSocial Email Confirmation"
)
func (s *sender) SendConfirmEmail(toAddress string, data ConfirmData) error {
buf := &bytes.Buffer{}
if err := s.template.ExecuteTemplate(buf, confirmTemplate, data); err != nil {
return err
}
confirmBody := buf.String()
msg, err := assembleMessage(confirmSubject, confirmBody, toAddress, s.from)
if err != nil {
return err
}
log.Trace(nil, s.hostAddress+"\n"+config.GetSMTPUsername()+":password"+"\n"+s.from+"\n"+toAddress+"\n\n"+string(msg)+"\n")
return smtp.SendMail(s.hostAddress, s.auth, s.from, []string{toAddress}, msg)
}
// ConfirmData represents data passed into the confirm email address template.
type ConfirmData struct {
// Username to be addressed.
@@ -57,3 +41,22 @@ type ConfirmData struct {
// Should be a full link with protocol eg., https://example.org/confirm_email?token=some-long-token
ConfirmLink string
}
func (s *sender) SendConfirmEmail(toAddress string, data ConfirmData) error {
buf := &bytes.Buffer{}
if err := s.template.ExecuteTemplate(buf, confirmTemplate, data); err != nil {
return err
}
confirmBody := buf.String()
msg, err := assembleMessage(confirmSubject, confirmBody, toAddress, s.from)
if err != nil {
return err
}
if err := smtp.SendMail(s.hostAddress, s.auth, s.from, []string{toAddress}, msg); err != nil {
return gtserror.SetType(err, gtserror.TypeSMTP)
}
return nil
}

View File

@@ -88,3 +88,24 @@ func (s *noopSender) SendResetEmail(toAddress string, data ResetData) error {
return nil
}
func (s *noopSender) SendTestEmail(toAddress string, data TestData) error {
buf := &bytes.Buffer{}
if err := s.template.ExecuteTemplate(buf, testTemplate, data); err != nil {
return err
}
testBody := buf.String()
msg, err := assembleMessage(testSubject, testBody, toAddress, "test@example.org")
if err != nil {
return err
}
log.Tracef(nil, "NOT SENDING test email to %s with contents: %s", toAddress, msg)
if s.sendCallback != nil {
s.sendCallback(toAddress, string(msg))
}
return nil
}

View File

@@ -20,6 +20,8 @@ package email
import (
"bytes"
"net/smtp"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
)
const (
@@ -27,20 +29,6 @@ const (
resetSubject = "GoToSocial Password Reset"
)
func (s *sender) SendResetEmail(toAddress string, data ResetData) error {
buf := &bytes.Buffer{}
if err := s.template.ExecuteTemplate(buf, resetTemplate, data); err != nil {
return err
}
resetBody := buf.String()
msg, err := assembleMessage(resetSubject, resetBody, toAddress, s.from)
if err != nil {
return err
}
return smtp.SendMail(s.hostAddress, s.auth, s.from, []string{toAddress}, msg)
}
// ResetData represents data passed into the reset email address template.
type ResetData struct {
// Username to be addressed.
@@ -53,3 +41,22 @@ type ResetData struct {
// Should be a full link with protocol eg., https://example.org/reset_password?token=some-reset-password-token
ResetLink string
}
func (s *sender) SendResetEmail(toAddress string, data ResetData) error {
buf := &bytes.Buffer{}
if err := s.template.ExecuteTemplate(buf, resetTemplate, data); err != nil {
return err
}
resetBody := buf.String()
msg, err := assembleMessage(resetSubject, resetBody, toAddress, s.from)
if err != nil {
return err
}
if err := smtp.SendMail(s.hostAddress, s.auth, s.from, []string{toAddress}, msg); err != nil {
return gtserror.SetType(err, gtserror.TypeSMTP)
}
return nil
}

View File

@@ -32,6 +32,9 @@ type Sender interface {
// SendResetEmail sends a 'reset your password' style email to the given toAddress, with the given data.
SendResetEmail(toAddress string, data ResetData) error
// SendTestEmail sends a 'testing email sending' style email to the given toAddress, with the given data.
SendTestEmail(toAddress string, data TestData) error
}
// NewSender returns a new email Sender interface with the given configuration, or an error if something goes wrong.

58
internal/email/test.go Normal file
View File

@@ -0,0 +1,58 @@
// 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"
"net/smtp"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
)
const (
testTemplate = "email_test_text.tmpl"
testSubject = "GoToSocial Test Email"
)
type TestData struct {
// Username of admin user who sent the test.
SendingUsername string
// URL of the instance to present to the receiver.
InstanceURL string
// Name of the instance to present to the receiver.
InstanceName string
}
func (s *sender) SendTestEmail(toAddress string, data TestData) error {
buf := &bytes.Buffer{}
if err := s.template.ExecuteTemplate(buf, testTemplate, data); err != nil {
return err
}
testBody := buf.String()
msg, err := assembleMessage(testSubject, testBody, toAddress, s.from)
if err != nil {
return err
}
if err := smtp.SendMail(s.hostAddress, s.auth, s.from, []string{toAddress}, msg); err != nil {
return gtserror.SetType(err, gtserror.TypeSMTP)
}
return nil
}