commit
188b41ef53
5 changed files with 103 additions and 34 deletions
10
app.go
10
app.go
|
@ -428,15 +428,11 @@ func Initialize(apper Apper, debug bool) (*App, error) {
|
||||||
|
|
||||||
initActivityPub(apper.App())
|
initActivityPub(apper.App())
|
||||||
|
|
||||||
if apper.App().cfg.Email.Domain != "" || apper.App().cfg.Email.MailgunPrivate != "" {
|
if apper.App().cfg.Email.Enabled() {
|
||||||
if apper.App().cfg.Email.Domain == "" {
|
|
||||||
log.Error("[FAILED] Starting publish jobs queue: no [letters]domain config value set.")
|
|
||||||
} else if apper.App().cfg.Email.MailgunPrivate == "" {
|
|
||||||
log.Error("[FAILED] Starting publish jobs queue: no [letters]mailgun_private config value set.")
|
|
||||||
} else {
|
|
||||||
log.Info("Starting publish jobs queue...")
|
log.Info("Starting publish jobs queue...")
|
||||||
go startPublishJobsQueue(apper.App())
|
go startPublishJobsQueue(apper.App())
|
||||||
}
|
} else {
|
||||||
|
log.Error("[FAILED] Starting publish jobs queue: no email provider is configured.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle local timeline, if enabled
|
// Handle local timeline, if enabled
|
||||||
|
|
|
@ -251,7 +251,8 @@ func (ac *AppCfg) LandingPath() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lc EmailCfg) Enabled() bool {
|
func (lc EmailCfg) Enabled() bool {
|
||||||
return lc.Domain != "" && lc.MailgunPrivate != ""
|
return (lc.Domain != "" && lc.MailgunPrivate != "") ||
|
||||||
|
lc.Username != "" && lc.Password != "" && lc.Host != "" && lc.Port > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ac AppCfg) SignupPath() string {
|
func (ac AppCfg) SignupPath() string {
|
||||||
|
|
23
email.go
23
email.go
|
@ -22,7 +22,6 @@ import (
|
||||||
|
|
||||||
"github.com/aymerick/douceur/inliner"
|
"github.com/aymerick/douceur/inliner"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/mailgun/mailgun-go"
|
|
||||||
stripmd "github.com/writeas/go-strip-markdown/v2"
|
stripmd "github.com/writeas/go-strip-markdown/v2"
|
||||||
"github.com/writeas/impart"
|
"github.com/writeas/impart"
|
||||||
"github.com/writeas/web-core/data"
|
"github.com/writeas/web-core/data"
|
||||||
|
@ -308,14 +307,14 @@ Originally published on ` + p.Collection.DisplayTitle() + ` (` + p.Collection.Ca
|
||||||
|
|
||||||
Sent to %recipient.to%. Unsubscribe: ` + p.Collection.CanonicalURL() + `email/unsubscribe/%recipient.id%?t=%recipient.token%`
|
Sent to %recipient.to%. Unsubscribe: ` + p.Collection.CanonicalURL() + `email/unsubscribe/%recipient.id%?t=%recipient.token%`
|
||||||
|
|
||||||
gun := mailgun.NewMailgun(app.cfg.Email.Domain, app.cfg.Email.MailgunPrivate)
|
mlr, err := mailer.New(app.cfg.Email)
|
||||||
|
if err != nil {
|
||||||
if app.cfg.Email.MailgunEurope {
|
return err
|
||||||
gun.SetAPIBase("https://api.eu.mailgun.net/v3")
|
}
|
||||||
|
m, err := mlr.NewMessage(p.Collection.DisplayTitle()+" <"+p.Collection.Alias+"@"+app.cfg.Email.Domain+">", stripmd.Strip(p.DisplayTitle()), plainMsg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
m := mailgun.NewMessage(p.Collection.DisplayTitle()+" <"+p.Collection.Alias+"@"+app.cfg.Email.Domain+">", stripmd.Strip(p.DisplayTitle()), plainMsg)
|
|
||||||
replyTo := app.db.GetCollectionAttribute(collID, collAttrLetterReplyTo)
|
replyTo := app.db.GetCollectionAttribute(collID, collAttrLetterReplyTo)
|
||||||
if replyTo != "" {
|
if replyTo != "" {
|
||||||
m.SetReplyTo(replyTo)
|
m.SetReplyTo(replyTo)
|
||||||
|
@ -412,13 +411,13 @@ Sent to %recipient.to%. Unsubscribe: ` + p.Collection.CanonicalURL() + `email/un
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
m.SetHtml(html)
|
m.SetHTML(html)
|
||||||
|
|
||||||
log.Info("[email] Adding %d recipient(s)", len(subs))
|
log.Info("[email] Adding %d recipient(s)", len(subs))
|
||||||
for _, s := range subs {
|
for _, s := range subs {
|
||||||
e := s.FinalEmail(app.keys)
|
e := s.FinalEmail(app.keys)
|
||||||
log.Info("[email] Adding %s", e)
|
log.Info("[email] Adding %s", e)
|
||||||
err = m.AddRecipientAndVariables(e, map[string]interface{}{
|
err = m.AddRecipientAndVariables(e, map[string]string{
|
||||||
"id": s.ID,
|
"id": s.ID,
|
||||||
"to": e,
|
"to": e,
|
||||||
"token": s.Token,
|
"token": s.Token,
|
||||||
|
@ -428,8 +427,8 @@ Sent to %recipient.to%. Unsubscribe: ` + p.Collection.CanonicalURL() + `email/un
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res, _, err := gun.Send(m)
|
err = mlr.Send(m)
|
||||||
log.Info("[email] Send result: %s", res)
|
log.Info("[email] Email sent")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Unable to send post email: %v", err)
|
log.Error("Unable to send post email: %v", err)
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -13,8 +13,10 @@ package mailer
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/mailgun/mailgun-go"
|
"github.com/mailgun/mailgun-go"
|
||||||
|
"github.com/writeas/web-core/log"
|
||||||
"github.com/writefreely/writefreely/config"
|
"github.com/writefreely/writefreely/config"
|
||||||
mail "github.com/xhit/go-simple-mail/v2"
|
mail "github.com/xhit/go-simple-mail/v2"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
@ -27,7 +29,21 @@ type (
|
||||||
// Message holds the email contents and metadata for the preferred mailing provider.
|
// Message holds the email contents and metadata for the preferred mailing provider.
|
||||||
Message struct {
|
Message struct {
|
||||||
mgMsg *mailgun.Message
|
mgMsg *mailgun.Message
|
||||||
smtpMsg *mail.Email
|
smtpMsg *SmtpMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
SmtpMessage struct {
|
||||||
|
from string
|
||||||
|
replyTo string
|
||||||
|
subject string
|
||||||
|
recipients []Recipient
|
||||||
|
html string
|
||||||
|
text string
|
||||||
|
}
|
||||||
|
|
||||||
|
Recipient struct {
|
||||||
|
email string
|
||||||
|
vars map[string]string
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -48,6 +64,8 @@ func New(eCfg config.EmailCfg) (*Mailer, error) {
|
||||||
if eCfg.EnableStartTLS {
|
if eCfg.EnableStartTLS {
|
||||||
m.smtp.Encryption = mail.EncryptionSTARTTLS
|
m.smtp.Encryption = mail.EncryptionSTARTTLS
|
||||||
}
|
}
|
||||||
|
// To allow sending multiple email
|
||||||
|
m.smtp.KeepAlive = true
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("no email provider is configured")
|
return nil, fmt.Errorf("no email provider is configured")
|
||||||
}
|
}
|
||||||
|
@ -61,14 +79,16 @@ func (m *Mailer) NewMessage(from, subject, text string, to ...string) (*Message,
|
||||||
if m.mailGun != nil {
|
if m.mailGun != nil {
|
||||||
msg.mgMsg = m.mailGun.NewMessage(from, subject, text, to...)
|
msg.mgMsg = m.mailGun.NewMessage(from, subject, text, to...)
|
||||||
} else if m.smtp != nil {
|
} else if m.smtp != nil {
|
||||||
msg.smtpMsg = mail.NewMSG()
|
msg.smtpMsg = &SmtpMessage{
|
||||||
msg.smtpMsg.SetFrom(from)
|
from: from,
|
||||||
msg.smtpMsg.AddTo(to...)
|
replyTo: "",
|
||||||
msg.smtpMsg.SetSubject(subject)
|
subject: subject,
|
||||||
msg.smtpMsg.AddAlternative(mail.TextPlain, text)
|
recipients: make([]Recipient, len(to)),
|
||||||
|
html: "",
|
||||||
if msg.smtpMsg.Error != nil {
|
text: text,
|
||||||
return nil, msg.smtpMsg.Error
|
}
|
||||||
|
for _, r := range to {
|
||||||
|
msg.smtpMsg.recipients = append(msg.smtpMsg.recipients, Recipient{r, make(map[string]string)})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return msg, nil
|
return msg, nil
|
||||||
|
@ -77,12 +97,20 @@ func (m *Mailer) NewMessage(from, subject, text string, to ...string) (*Message,
|
||||||
// SetHTML sets the body of the message.
|
// SetHTML sets the body of the message.
|
||||||
func (m *Message) SetHTML(html string) {
|
func (m *Message) SetHTML(html string) {
|
||||||
if m.smtpMsg != nil {
|
if m.smtpMsg != nil {
|
||||||
m.smtpMsg.SetBody(mail.TextHTML, html)
|
m.smtpMsg.html = html
|
||||||
} else if m.mgMsg != nil {
|
} else if m.mgMsg != nil {
|
||||||
m.mgMsg.SetHtml(html)
|
m.mgMsg.SetHtml(html)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Message) SetReplyTo(replyTo string) {
|
||||||
|
if m.smtpMsg != nil {
|
||||||
|
m.smtpMsg.replyTo = replyTo
|
||||||
|
} else {
|
||||||
|
m.mgMsg.SetReplyTo(replyTo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// AddTag attaches a tag to the Message for providers that support it.
|
// AddTag attaches a tag to the Message for providers that support it.
|
||||||
func (m *Message) AddTag(tag string) {
|
func (m *Message) AddTag(tag string) {
|
||||||
if m.mgMsg != nil {
|
if m.mgMsg != nil {
|
||||||
|
@ -90,6 +118,19 @@ func (m *Message) AddTag(tag string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Message) AddRecipientAndVariables(r string, vars map[string]string) error {
|
||||||
|
if m.smtpMsg != nil {
|
||||||
|
m.smtpMsg.recipients = append(m.smtpMsg.recipients, Recipient{r, vars})
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
varsInterfaces := make(map[string]interface{}, len(vars))
|
||||||
|
for k, v := range vars {
|
||||||
|
varsInterfaces[k] = v
|
||||||
|
}
|
||||||
|
return m.mgMsg.AddRecipientAndVariables(r, varsInterfaces)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Send sends the given message via the preferred provider.
|
// Send sends the given message via the preferred provider.
|
||||||
func (m *Mailer) Send(msg *Message) error {
|
func (m *Mailer) Send(msg *Message) error {
|
||||||
if m.smtp != nil {
|
if m.smtp != nil {
|
||||||
|
@ -97,7 +138,39 @@ func (m *Mailer) Send(msg *Message) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return msg.smtpMsg.Send(client)
|
emailSent := false
|
||||||
|
for _, r := range msg.smtpMsg.recipients {
|
||||||
|
customMsg := mail.NewMSG()
|
||||||
|
customMsg.SetFrom(msg.smtpMsg.from)
|
||||||
|
if msg.smtpMsg.replyTo != "" {
|
||||||
|
customMsg.SetReplyTo(msg.smtpMsg.replyTo)
|
||||||
|
}
|
||||||
|
customMsg.SetSubject(msg.smtpMsg.subject)
|
||||||
|
customMsg.AddTo(r.email)
|
||||||
|
cText := msg.smtpMsg.text
|
||||||
|
cHtml := msg.smtpMsg.html
|
||||||
|
for v, value := range r.vars {
|
||||||
|
placeHolder := fmt.Sprintf("%%recipient.%s%%", v)
|
||||||
|
cText = strings.ReplaceAll(cText, placeHolder, value)
|
||||||
|
cHtml = strings.ReplaceAll(cHtml, placeHolder, value)
|
||||||
|
}
|
||||||
|
customMsg.SetBody(mail.TextHTML, cHtml)
|
||||||
|
customMsg.AddAlternative(mail.TextPlain, cText)
|
||||||
|
e := customMsg.Error
|
||||||
|
if e == nil {
|
||||||
|
e = customMsg.Send(client)
|
||||||
|
}
|
||||||
|
if e == nil {
|
||||||
|
emailSent = true
|
||||||
|
} else {
|
||||||
|
log.Error("Unable to send email to %s: %v", r.email, e)
|
||||||
|
err = e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !emailSent {
|
||||||
|
// only send an error if no email could be sent (to avoid retry of successfully sent emails)
|
||||||
|
return err
|
||||||
|
}
|
||||||
} else if m.mailGun != nil {
|
} else if m.mailGun != nil {
|
||||||
_, _, err := m.mailGun.Send(msg.mgMsg)
|
_, _, err := m.mailGun.Send(msg.mgMsg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -14,8 +14,8 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue