From 8954318e400a69ac1116184156c8090b43d922ec Mon Sep 17 00:00:00 2001 From: Maxime Delporte Date: Sun, 30 Nov 2025 17:22:32 +0100 Subject: [PATCH] Adding godotenv library to use our .env file for the smtp configuration. Updating main.go adding our logger first, load our .env file, retrieve values to initialize the mail application's struct. Updating registerUserHandler sending the user_welcome.tmpl email. --- cmd/api/main.go | 40 +++++++++++++++++++++++++++++++++++++--- cmd/api/users.go | 7 +++++++ go.mod | 1 + go.sum | 2 ++ 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/cmd/api/main.go b/cmd/api/main.go index c57a426..4e3894f 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -6,9 +6,12 @@ import ( "flag" "log/slog" "os" + "strconv" "time" + "github.com/joho/godotenv" "greenlight.craftr.fr/internal/data" + "greenlight.craftr.fr/internal/mailer" // Import the pq driver so that it can register itself with the database/sql package. Note that we alias this import to the blank identifier, to stop the Go compiler complaining that the package isn't being used. _ "github.com/lib/pq" @@ -44,6 +47,13 @@ type config struct { burst int enabled bool } + smtp struct { + host string + port int + username string + password string + sender string + } } // application struct hold the dependencies for our HTTP handlers, helpers, and middleware. @@ -51,9 +61,18 @@ type application struct { config config logger *slog.Logger models data.Models + mailer mailer.Mailer } func main() { + // Initialize a new structured logger which writes log entries to standard out stream. + logger := slog.New(slog.NewTextHandler(os.Stdout, nil)) + + err := godotenv.Load() + if err != nil { + logger.Error("Error loading .env file") + } + // Declare an instance of the config struct. var cfg config @@ -78,10 +97,24 @@ func main() { flag.IntVar(&cfg.limiter.burst, "limiter-burst", 4, "Rate limiter maximum burst") flag.BoolVar(&cfg.limiter.enabled, "limiter-enabled", true, "Enable rate limiter") - flag.Parse() + smtpHost := os.Getenv("SMTP_HOST") + smtpPort := os.Getenv("SMTP_PORT") + smtpPortInt, err := strconv.Atoi(smtpPort) + if err != nil { + logger.Error("couldn't convert smtpPort to integer.") + } + smtpUsername := os.Getenv("SMTP_USERNAME") + smtpPassword := os.Getenv("SMTP_PASSWORD") + smtpSender := os.Getenv("SMTP_SENDER") - // Initialize a new structured logger which writes log entries to standard out stream. - logger := slog.New(slog.NewTextHandler(os.Stdout, nil)) + // Read the SMTP server configuration settings into the config struct, using the Mailtrap settings as the default values. + flag.StringVar(&cfg.smtp.host, "smtp-host", smtpHost, "SMTP host") + flag.IntVar(&cfg.smtp.port, "smtp-port", smtpPortInt, "SMTP port") + flag.StringVar(&cfg.smtp.username, "smtp-username", smtpUsername, "SMTP username") + flag.StringVar(&cfg.smtp.password, "smtp-password", smtpPassword, "SMTP password") + flag.StringVar(&cfg.smtp.sender, "smtp-sender", smtpSender, "SMTP sender") + + flag.Parse() // Call the openDB() helper function to create the connection pool, passing in the config struct. If this returns an error, we log it and exit the application immediately. db, err := openDB(cfg) @@ -101,6 +134,7 @@ func main() { config: cfg, logger: logger, models: data.NewModels(db), + mailer: mailer.New(cfg.smtp.host, cfg.smtp.port, cfg.smtp.username, cfg.smtp.password, cfg.smtp.sender), } // Call app.serve() to start the server. diff --git a/cmd/api/users.go b/cmd/api/users.go index b74be07..1d3fce1 100644 --- a/cmd/api/users.go +++ b/cmd/api/users.go @@ -59,6 +59,13 @@ func (app *application) registerUserHandler(w http.ResponseWriter, r *http.Reque return } + // Call the Send() method on our Mail, passing in the user's email address, name of the template file, and the User struct containing the new user's data. + err = app.mailer.Send(user.Email, "user_welcome.tmpl", user) + if err != nil { + app.serverErrorResponse(w, r, err) + return + } + // Write a JSON response containing the user data along with a 201 Created status code err = app.writeJSON(w, http.StatusCreated, envelope{"user": user}, nil) if err != nil { diff --git a/go.mod b/go.mod index 1057413..7ed9f92 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.25.1 require ( github.com/go-mail/mail/v2 v2.3.0 // indirect + github.com/joho/godotenv v1.5.1 // indirect github.com/julienschmidt/httprouter v1.3.0 // indirect github.com/lib/pq v1.10.9 // indirect golang.org/x/crypto v0.45.0 // indirect diff --git a/go.sum b/go.sum index 9e6fc28..8cf96f9 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ 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/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=