Adding go-mail package instead of using internal go package. Defining a mailer package to send our emails.
This commit is contained in:
2
go.mod
2
go.mod
@@ -3,8 +3,10 @@ module greenlight.craftr.fr
|
|||||||
go 1.25.1
|
go 1.25.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/go-mail/mail/v2 v2.3.0 // indirect
|
||||||
github.com/julienschmidt/httprouter v1.3.0 // indirect
|
github.com/julienschmidt/httprouter v1.3.0 // indirect
|
||||||
github.com/lib/pq v1.10.9 // indirect
|
github.com/lib/pq v1.10.9 // indirect
|
||||||
golang.org/x/crypto v0.45.0 // indirect
|
golang.org/x/crypto v0.45.0 // indirect
|
||||||
golang.org/x/time v0.14.0 // indirect
|
golang.org/x/time v0.14.0 // indirect
|
||||||
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -1,3 +1,5 @@
|
|||||||
|
github.com/go-mail/mail/v2 v2.3.0 h1:wha99yf2v3cpUzD1V9ujP404Jbw2uEvs+rBJybkdYcw=
|
||||||
|
github.com/go-mail/mail/v2 v2.3.0/go.mod h1:oE2UK8qebZAjjV1ZYUpY7FPnbi/kIU53l1dmqPRb4go=
|
||||||
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
|
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
|
||||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
@@ -6,3 +8,5 @@ golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
|||||||
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
||||||
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
||||||
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||||
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||||
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||||
|
|||||||
78
internal/mailer/mailer.go
Normal file
78
internal/mailer/mailer.go
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
package mailer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"embed"
|
||||||
|
"html/template"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-mail/mail/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Below we declare a new variable with the type embed.FS (embedded file system) to hold our email templates. This has a comment directive in the format `//go:embed <path>` IMMEDIATELY ABOVE it, which indicates to Go that we want to store the contents of the ./templates directory in the templateFS embedded file system variable.
|
||||||
|
|
||||||
|
//go:embed "templates"
|
||||||
|
var templateFS embed.FS
|
||||||
|
|
||||||
|
// Mailer struct contains a mail.Dialer instance (used to connect to a SMTP server) and the sender information for your emails (the name and address you want the email to be from, such as "Alice Smith <alice@example.com>")
|
||||||
|
type Mailer struct {
|
||||||
|
dialer *mail.Dialer
|
||||||
|
sender string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(host string, port int, username, password, sender string) Mailer {
|
||||||
|
// Initialize a new mail.Dialer instance with the given SMTP server settings. We also configure this to use a 5-second timeout whenever we send the email.
|
||||||
|
dialer := mail.NewDialer(host, port, username, password)
|
||||||
|
dialer.Timeout = 5 * time.Second
|
||||||
|
|
||||||
|
return Mailer{
|
||||||
|
dialer: dialer,
|
||||||
|
sender: sender,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send method on the Mailer type. This takes the recipient email address as the first parameter, the name of the file containing the templates, and any dynamic data for the templates as an any parameter
|
||||||
|
func (m Mailer) Send(recipient, templateFile string, data any) error {
|
||||||
|
// Use the ParseFS() method to parse the required template file from the embedded file system
|
||||||
|
tmpl, err := template.New("email").ParseFS(templateFS, "templates/"+templateFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute the named template "subject", passing in the dynamic data and storing the result in a bytes.Buffer variable
|
||||||
|
subject := new(bytes.Buffer)
|
||||||
|
err = tmpl.ExecuteTemplate(subject, "subject", data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Follow the same pattern to execute the "plainBody" template and store the result in the plainBody variable
|
||||||
|
plainBody := new(bytes.Buffer)
|
||||||
|
err = tmpl.ExecuteTemplate(plainBody, "plainBody", data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// And likewise with the "htmlBody" template
|
||||||
|
htmlBody := new(bytes.Buffer)
|
||||||
|
err = tmpl.ExecuteTemplate(htmlBody, "htmlBody", data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the mail.NewMessage() function to initialize a new mail.Message instance. Then we use the SetHeader() method to set the email recipient, sender and subject headers, the SetBody() method to set the plain-text body, and the AddAlternative() method to set the HTML body. It's important to note that AddAlternative(à should always be called *after* SetBody()
|
||||||
|
msg := mail.NewMessage()
|
||||||
|
msg.SetHeader("To", recipient)
|
||||||
|
msg.SetHeader("From", m.sender)
|
||||||
|
msg.SetHeader("Subject", subject.String())
|
||||||
|
msg.SetBody("text/plain", plainBody.String())
|
||||||
|
msg.AddAlternative("text/html", htmlBody.String())
|
||||||
|
|
||||||
|
// Call the DialAndSend() method on the dialer, passing in the message to send. This opens a connection to the SMTP server, sends the message, then closes the connection. If there is a timeout, it will return a "dial tcp: i/o timeout" error
|
||||||
|
err = m.dialer.DialAndSend(msg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
31
internal/mailer/templates/user_welcome.tmpl
Normal file
31
internal/mailer/templates/user_welcome.tmpl
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{{define "subject"}}Welcome to Greenlight!{{end}}
|
||||||
|
|
||||||
|
{{define "plainBody"}}
|
||||||
|
Hi,
|
||||||
|
|
||||||
|
Thanks for signing up for a Greenlight account. We're excited to have you on board!
|
||||||
|
|
||||||
|
For future reference, your user ID number is {{.ID}}.
|
||||||
|
|
||||||
|
Thanks,
|
||||||
|
|
||||||
|
The Greenlight Team
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{define "htmlBody"}}
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<title></title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>Hi,</p>
|
||||||
|
<p>Thanks for signing up for a Greenlight account. We're excited to have you on board!</p>
|
||||||
|
<p>For future reference, your user ID number is {{.ID}}.</p>
|
||||||
|
<p>Thanks,</p>
|
||||||
|
<p>The Greenlight Team</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
{{end}}
|
||||||
Reference in New Issue
Block a user