dnote/pkg/server/mailer/mailer.go
Sung Won Cho 23a511dbe0
Improve package structure (#207)
* Improve package structure

* Set up travis
2019-06-25 19:20:19 +10:00

147 lines
4 KiB
Go

/* Copyright (C) 2019 Monomax Software Pty Ltd
*
* This file is part of Dnote.
*
* Dnote 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.
*
* Dnote 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 Dnote. If not, see <https://www.gnu.org/licenses/>.
*/
// Package mailer provides a functionality to send emails
package mailer
import (
"bytes"
"fmt"
"html/template"
"os"
"path"
"github.com/aymerick/douceur/inliner"
"github.com/pkg/errors"
"gopkg.in/gomail.v2"
)
// Email represents email to be sent out
type Email struct {
from string
to []string
subject string
Body string
}
var (
// T is a map of templates
T = map[string]*template.Template{}
// EmailTypeWeeklyDigest represents a weekly digest email
EmailTypeWeeklyDigest = "weekly_digest"
// EmailTypeEmailVerification represents an email verification email
EmailTypeEmailVerification = "email_verification"
)
func getTemplatePath(templateDirPath, filename string) string {
return path.Join(templateDirPath, fmt.Sprintf("%s.html", filename))
}
// initTemplate returns a template instance by parsing the template with the
// given name along with partials
func initTemplate(templateDirPath, templateFileName string) (*template.Template, error) {
templatePath := getTemplatePath(templateDirPath, templateFileName)
headerPath := getTemplatePath(templateDirPath, "header")
footerPath := getTemplatePath(templateDirPath, "footer")
t, err := template.ParseFiles(templatePath, headerPath, footerPath)
if err != nil {
return nil, errors.Wrap(err, "parseing template")
}
return t, nil
}
// InitTemplates initializes templates
func InitTemplates(templateDirPath string) {
weeklyDigestTmpl, err := initTemplate(templateDirPath, EmailTypeWeeklyDigest)
if err != nil {
panic(errors.Wrap(err, "initializing template"))
}
emailVerificationTmpl, err := initTemplate(templateDirPath, EmailTypeEmailVerification)
if err != nil {
panic(errors.Wrap(err, "initializing template"))
}
T[EmailTypeWeeklyDigest] = weeklyDigestTmpl
T[EmailTypeEmailVerification] = emailVerificationTmpl
}
// NewEmail returns a pointer to an Email struct with the given data
func NewEmail(from string, to []string, subject string) *Email {
return &Email{
from: from,
to: to,
subject: subject,
}
}
// isWhitelisted checks if the email is safe to send in non production env
func isWhitelisted(emails []string) bool {
return false
// return len(emails) == 1 && emails[0] == "mikeswcho@gmail.com"
}
// Send sends the email
func (e *Email) Send() error {
// If not production, never actually send an email
if os.Getenv("GO_ENV") != "PRODUCTION" {
fmt.Println("Not sending email because not production")
fmt.Println(e.subject, e.to, e.from)
// fmt.Println("Body", e.Body)
return nil
}
smtpPort := 465
m := gomail.NewMessage()
m.SetHeader("From", e.from)
m.SetHeader("To", e.to...)
m.SetHeader("Subject", e.subject)
m.SetBody("text/html", e.Body)
d := gomail.NewPlainDialer(os.Getenv("SmtpHost"), smtpPort, os.Getenv("SmtpUsername"), os.Getenv("SmtpPassword"))
if err := d.DialAndSend(m); err != nil {
return err
}
return nil
}
// ParseTemplate sets the email body by parsing the file at the given path,
// evaluating all partials and inlining CSS rules
func (e *Email) ParseTemplate(templateName string, data interface{}) error {
t := T[templateName]
if t == nil {
return errors.Errorf("unsupported template '%s'", templateName)
}
buf := new(bytes.Buffer)
if err := t.Execute(buf, data); err != nil {
return err
}
html, err := inliner.Inline(buf.String())
if err != nil {
return err
}
e.Body = html
return nil
}