multipart for text fallback
parent
4605629545
commit
0e632d00f7
|
@ -21,14 +21,14 @@ func Init() {
|
|||
func NewMail(mail structs.Mail) error {
|
||||
gocnjhelper.LogDebug("NEW MAIL")
|
||||
|
||||
body, err := mail.RenderTemplate()
|
||||
htmlBody, textBody, err := mail.RenderTemplate()
|
||||
|
||||
if err != nil {
|
||||
gocnjhelper.LogErrorf("Failed to render template, err: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err = mail.Send(body); err != nil {
|
||||
if err = mail.Send(htmlBody, textBody); err != nil {
|
||||
gocnjhelper.LogErrorf("Failed to send mail, err: %s", err)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -31,7 +31,13 @@ func loadTemplateFiles() {
|
|||
gocnjhelper.LogDebug("STARTING IMPORTING TEMPLATE FILES")
|
||||
|
||||
for templateName := range cache.Templates.Templates {
|
||||
data, err := os.ReadFile(config.Cfg.Templates.FolderPath + templateName + ".html")
|
||||
dataHtml, err := os.ReadFile(config.Cfg.Templates.FolderPath + templateName + ".html")
|
||||
|
||||
if err != nil {
|
||||
gocnjhelper.LogFatalf("Failed to read file, err: %s", err)
|
||||
}
|
||||
|
||||
dataTxt, err := os.ReadFile(config.Cfg.Templates.FolderPath + templateName + ".txt")
|
||||
|
||||
if err != nil {
|
||||
gocnjhelper.LogFatalf("Failed to read file, err: %s", err)
|
||||
|
@ -45,7 +51,11 @@ func loadTemplateFiles() {
|
|||
|
||||
// cache.BodyTemplates[templateName] = []byte(minifiedHtml)
|
||||
|
||||
cache.BodyTemplates[templateName] = []byte(data)
|
||||
//cache.BodyTemplates[templateName] = []byte(data)
|
||||
cache.BodyTemplates[templateName] = cache.BodyContentTemplate{
|
||||
HTML: dataHtml,
|
||||
PlainText: dataTxt,
|
||||
}
|
||||
}
|
||||
|
||||
gocnjhelper.LogDebug("FINISHED IMPORTING TEMPLATE FILES")
|
||||
|
|
|
@ -6,7 +6,12 @@ type templates struct {
|
|||
Templates map[string]map[string]map[string]string
|
||||
}
|
||||
|
||||
type BodyContentTemplate struct {
|
||||
HTML []byte
|
||||
PlainText []byte // fallback if html is not supported
|
||||
}
|
||||
|
||||
var Templates templates
|
||||
var BodyTemplates = make(map[string][]byte)
|
||||
var BodyTemplates = make(map[string]BodyContentTemplate)
|
||||
|
||||
var SmtpAuth smtp.Auth
|
||||
|
|
|
@ -24,16 +24,30 @@ type Mail struct {
|
|||
BodyData interface{}
|
||||
}
|
||||
|
||||
func (m *Mail) Send(body string) error {
|
||||
func (m *Mail) Send(htmlBody, textBody string) error {
|
||||
cfg := config.Cfg.Mail
|
||||
|
||||
// Generate unique message ID
|
||||
messageID := uuid.New().String() + "@" + strings.Split(cfg.FromEmail, "@")[1]
|
||||
|
||||
// Generate unique boundary string
|
||||
boundary := "boundary" + uuid.New().String()
|
||||
|
||||
// Create MIME message with multipart/alternative content type
|
||||
msg := "From: " + cfg.FromName + " <" + cfg.FromEmail + ">\n" +
|
||||
"To: " + strings.Join(m.To, ",") + "\n" +
|
||||
"Subject: " + m.Subject + "\n" +
|
||||
"Date: " + time.Now().Format("Mon, 02 Jan 2006 15:04:05 -0700") + "\n" +
|
||||
"Message-ID: <" + uuid.New().String() + "@" + strings.Split(cfg.FromEmail, "@")[1] + ">\n" +
|
||||
"MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n" +
|
||||
body
|
||||
"Message-ID: <" + messageID + ">\n" +
|
||||
"MIME-version: 1.0;\n" +
|
||||
"Content-Type: multipart/alternative; boundary=" + boundary + "\n\n" +
|
||||
"--" + boundary + "\n" +
|
||||
"Content-Type: text/plain; charset=\"UTF-8\"\n\n" +
|
||||
textBody + "\n\n" +
|
||||
"--" + boundary + "\n" +
|
||||
"Content-Type: text/html; charset=\"UTF-8\"\n\n" +
|
||||
htmlBody + "\n\n" +
|
||||
"--" + boundary + "--"
|
||||
|
||||
err := smtp.SendMail(cfg.Host+":"+cfg.Port, cache.SmtpAuth, cfg.FromEmail, m.To, []byte(msg))
|
||||
|
||||
|
@ -46,6 +60,94 @@ func (m *Mail) Send(body string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
func (m *Mail) Send(body string) error {
|
||||
cfg := config.Cfg.Mail
|
||||
|
||||
msg := "From: " + cfg.FromName + " <" + cfg.FromEmail + ">\n" +
|
||||
"To: " + strings.Join(m.To, ",") + "\n" +
|
||||
"Subject: " + m.Subject + "\n" +
|
||||
"Date: " + time.Now().Format("Mon, 02 Jan 2006 15:04:05 -0700") + "\n" +
|
||||
"Message-ID: <" + uuid.New().String() + "@" + strings.Split(cfg.FromEmail, "@")[1] + ">\n" +
|
||||
"MIME-version: 1.0;\nContent-Type: multipart/alternative; charset=\"UTF-8\";\n\n" +
|
||||
body
|
||||
|
||||
err := smtp.SendMail(cfg.Host+":"+cfg.Port, cache.SmtpAuth, cfg.FromEmail, m.To, []byte(msg))
|
||||
|
||||
if err != nil {
|
||||
gocnjhelper.LogErrorf("smtp error: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
gocnjhelper.LogDebugf("SEND MAIL %s", msg)
|
||||
return nil
|
||||
} */
|
||||
|
||||
func (m *Mail) RenderTemplate() (htmlBody, textBody string, err error) {
|
||||
body := cache.BodyTemplates[m.TemplateId]
|
||||
|
||||
for templateName, templateData := range cache.Templates.Templates {
|
||||
// Skipping templates if the template ID is not the expected one
|
||||
if templateName != m.TemplateId {
|
||||
continue
|
||||
}
|
||||
|
||||
gocnjhelper.LogDebugf("RENDER TEMPLATE %s %s", templateName, templateData)
|
||||
|
||||
m.Subject = templateData["mailSubject"][m.LanguageId]
|
||||
|
||||
// occurs if the requested language code does not exist
|
||||
if m.Subject == "" {
|
||||
m.Subject = templateData["mailSubject"][config.Cfg.DefaultLanguageCode]
|
||||
}
|
||||
|
||||
// replace body %values% with values in templates config
|
||||
for key, value := range templateData {
|
||||
if key == "mailSubject" {
|
||||
continue
|
||||
}
|
||||
|
||||
v := value[m.LanguageId]
|
||||
|
||||
// occurs if the requested language code does not exist
|
||||
if v == "" {
|
||||
v = value[config.Cfg.DefaultLanguageCode]
|
||||
}
|
||||
|
||||
// escaping so that umlauts are displayed correctly
|
||||
if m.LanguageId == "de" {
|
||||
v = escaper.EscapeHtmlEntites(v)
|
||||
}
|
||||
|
||||
body.HTML = []byte(strings.Replace(string(body.HTML), "%"+key+"%", v, -1))
|
||||
}
|
||||
}
|
||||
|
||||
// The subject line of an email is an independent header and utf 8 must be set for it
|
||||
// https://ncona.com/2011/06/using-utf-8-characters-on-an-e-mail-subject/
|
||||
if m.LanguageId == "de" {
|
||||
m.Subject = EncodeBase64(m.Subject)
|
||||
}
|
||||
|
||||
// Separate rendering for HTML and text bodies
|
||||
htmlTemplate := template.Must(template.New("").Parse(string(body.HTML)))
|
||||
textTemplate := template.Must(template.New("").Parse(string(body.PlainText)))
|
||||
|
||||
htmlBuf := new(bytes.Buffer)
|
||||
textBuf := new(bytes.Buffer)
|
||||
|
||||
if err := htmlTemplate.Execute(htmlBuf, m.BodyData); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
if err := textTemplate.Execute(textBuf, m.BodyData); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return htmlBuf.String(), textBuf.String(), nil
|
||||
}
|
||||
|
||||
/*
|
||||
func (m *Mail) RenderTemplate() (string, error) {
|
||||
body := cache.BodyTemplates[m.TemplateId]
|
||||
|
||||
|
@ -82,19 +184,17 @@ func (m *Mail) RenderTemplate() (string, error) {
|
|||
v = escaper.EscapeHtmlEntites(v)
|
||||
}
|
||||
|
||||
body = []byte(strings.Replace(string(body), "%"+key+"%", v, -1))
|
||||
body.HTML = []byte(strings.Replace(string(body.HTML), "%"+key+"%", v, -1))
|
||||
}
|
||||
}
|
||||
|
||||
// The subject line of an email is an independent header and utf 8 must be set for it
|
||||
// https://ncona.com/2011/06/using-utf-8-characters-on-an-e-mail-subject/
|
||||
if m.LanguageId == "de" {
|
||||
//m.Subject = "=?utf-8?B?" + base64.StdEncoding.EncodeToString([]byte(m.Subject)) + "?="
|
||||
|
||||
m.Subject = EncodeBase64(m.Subject)
|
||||
}
|
||||
|
||||
t := template.Must(template.New("").Parse(string(body)))
|
||||
t := template.Must(template.New("").Parse(string(body.HTML)))
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
|
@ -103,7 +203,7 @@ func (m *Mail) RenderTemplate() (string, error) {
|
|||
}
|
||||
|
||||
return buf.String(), nil
|
||||
}
|
||||
} */
|
||||
|
||||
// https://ncona.com/2011/06/using-utf-8-characters-on-an-e-mail-subject/
|
||||
func EncodeBase64(s string) string {
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<body>
|
||||
<h1>%header%</h1>
|
||||
<p>%informationText%</p>
|
||||
</body>
|
||||
</html>
|
|
@ -1,9 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<body>
|
||||
<h1>%header%</h1>
|
||||
<p>%informationText%</p>
|
||||
<p><b>{{.activation_code}}</b></p>
|
||||
<p>%codeUse%</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,12 @@
|
|||
%title%
|
||||
%header%
|
||||
%text1%
|
||||
{{.verifyURL}}
|
||||
%cancelText%
|
||||
%yourAppointment%
|
||||
%appointment1%
|
||||
%appointment2%
|
||||
%appointment3%
|
||||
{{.address}}
|
||||
%footer%
|
||||
%dsgvo%
|
|
@ -0,0 +1,11 @@
|
|||
%title%
|
||||
%header%
|
||||
%text1%
|
||||
|
||||
%yourAppointment%
|
||||
%appointment1%
|
||||
%appointment2%
|
||||
%appointment3%
|
||||
{{.address}}
|
||||
|
||||
%dsgvo%
|
|
@ -1,7 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<body>
|
||||
<h1>%header%</h1>
|
||||
<p>%informationText%</p>
|
||||
</body>
|
||||
</html>
|
|
@ -1,23 +1,5 @@
|
|||
{
|
||||
"templates": {
|
||||
"emailVerification": {
|
||||
"mailSubject": {
|
||||
"en": "Your email confirmation code",
|
||||
"de": "Ihr E-Mail-Bestätigungscode"
|
||||
},
|
||||
"header": {
|
||||
"en": "Good day,",
|
||||
"de": "Guten Tag,"
|
||||
},
|
||||
"informationText": {
|
||||
"en": "to confirm your identity we need to verify your email.",
|
||||
"de": "um deine Identität zu bestätigen müssen wir deine E-Mail verifizieren."
|
||||
},
|
||||
"codeUse": {
|
||||
"en": "Please enter this code in the app",
|
||||
"de": "Bitte gebe diesen Code in der App ein"
|
||||
}
|
||||
},
|
||||
"emailVerifyFailed": {
|
||||
"mailSubject": {
|
||||
"de": "Ihre Buchung wurde storniert"
|
||||
|
@ -89,34 +71,6 @@
|
|||
"dsgvo": {
|
||||
"de": "Datenschutzerklärung"
|
||||
}
|
||||
},
|
||||
"newUserSignIn": {
|
||||
"mailSubject": {
|
||||
"en": "A new sign-in was detected",
|
||||
"de": "Neue Anmeldung wurde festgestellt"
|
||||
},
|
||||
"header": {
|
||||
"en": "Good day,",
|
||||
"de": "Guten Tag,"
|
||||
},
|
||||
"informationText": {
|
||||
"en": "a new sign-in on <b>{{.device}}</b> was detected",
|
||||
"de": "eine neue Anmeldung auf <b>{{.device}}</b> wurde festgestellt"
|
||||
}
|
||||
},
|
||||
"SignUpSecondStep": {
|
||||
"mailSubject": {
|
||||
"en": "Welcome",
|
||||
"de": "Willkommen"
|
||||
},
|
||||
"header": {
|
||||
"en": "Good day {{.account_name}},",
|
||||
"de": "Guten Tag {{.account_name}},"
|
||||
},
|
||||
"informationText": {
|
||||
"en": "nice that you are here! Your account is created and you can start right away",
|
||||
"de": "schön das du da bist! Dein Account ist erstellt und du kannst sofort loslegen"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue