forked from LunaNode/lobster
-
Notifications
You must be signed in to change notification settings - Fork 0
/
email.go
165 lines (138 loc) · 3.52 KB
/
email.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package lobster
import "github.com/LunaNode/email"
import "bytes"
import "errors"
import "fmt"
import "io/ioutil"
import "log"
import "net/smtp"
import "strings"
import "text/template"
type EmailParams struct {
UserId int
Username string
Email string
UrlBase string
Params interface{}
}
type ErrorEmail struct {
Error string
Description string
Detail string
}
type LowCreditEmail struct {
Credit int64
Hourly int64
RemainingHours int
}
type VmUnsuspendEmail struct {
Name string
}
type VmDeletedEmail struct {
Id int
Name string
}
type VmCreateEmail struct {
Id int
Name string
}
type VmCreateErrorEmail struct {
Id int
Name string
}
type PaymentProcessedEmail *Transaction
type AccountCreatedEmail struct {
UserId int
Username string
Email string
}
type BandwidthUsageEmail struct {
UtilPercent int
Region string
Fee int64
}
type PwresetRequestEmail string
var emailTemplate *template.Template
func loadEmail() {
contents, _ := ioutil.ReadDir("tmpl/email")
templatePaths := make([]string, 0)
for _, fileInfo := range contents {
if fileInfo.Mode().IsRegular() && strings.HasSuffix(fileInfo.Name(), ".txt") {
templatePaths = append(templatePaths, "tmpl/email/"+fileInfo.Name())
}
}
emailTemplate = template.Must(template.New("").Funcs(template.FuncMap(templateFuncMap())).ParseFiles(templatePaths...))
}
func ReportError(err error, description string, detail string) {
if err != nil {
if detail != "" {
log.Println(detail)
}
log.Printf(fmt.Sprintf("%s: error: %s", description, err))
// the mail operation may itself generate an error, but we don't recursively report it
suberr := mail(-1, "error", ErrorEmail{Error: err.Error(), Description: description, Detail: detail}, false)
if suberr != nil {
log.Printf("ReportError: failed to report: %s", suberr)
}
}
}
func mail(userId int, tmpl string, subparams interface{}, ccAdmin bool) error {
toAddress := cfg.Default.AdminEmail
username := "N/A"
if userId >= 0 {
user := UserDetails(userId)
if user == nil {
return errors.New("user does not exist")
}
if user.Status != "new" {
toAddress = user.Email
} else {
toAddress = ""
}
username = user.Username
if toAddress == "" && !ccAdmin {
return nil
}
}
params := EmailParams{
UserId: userId,
Username: username,
Email: toAddress,
UrlBase: cfg.Default.UrlBase,
Params: subparams,
}
var buffer bytes.Buffer
err := emailTemplate.ExecuteTemplate(&buffer, tmpl+".txt", params)
if err != nil {
return err
}
templateParts := strings.SplitN(buffer.String(), "\n\n", 2)
if len(templateParts) != 2 {
return errors.New("template output does not include subject/body separator")
}
e := email.NewEmail()
e.From = cfg.Default.FromEmail
if toAddress != "" {
e.To = []string{toAddress}
}
if ccAdmin {
e.Bcc = []string{cfg.Default.AdminEmail}
}
e.Subject = templateParts[0]
e.Text = []byte(templateParts[1])
var auth smtp.Auth
if cfg.Email.Username != "" {
auth = smtp.PlainAuth("", cfg.Email.Username, cfg.Email.Password, cfg.Email.Host)
}
log.Printf("Sending email [%s] to [%s]", e.Subject, toAddress)
return e.Send(cfg.Email.Host, cfg.Email.Port, auth, cfg.Email.NoTLS)
}
func MailWrap(userId int, tmpl string, subparams interface{}, ccAdmin bool) {
go func() {
defer errorHandler(nil, nil, true)
err := mail(userId, tmpl, subparams, ccAdmin)
if err != nil {
ReportError(err, "failed to send email", fmt.Sprintf("userid=%d, tmpl=%s, subparam=%v", userId, tmpl, subparams))
}
}()
}