feat(mail): #132 unify env variables and send mails with smtp
This commit was merged in pull request #153.
This commit is contained in:
@@ -35,3 +35,10 @@ As of 2024 there are 4 options:
|
||||
Even though I would really implement authentication myself, I think OAuth2 with external providers is the best bet. Especially because my reasoning is privacy, which most people just don't care about enough. Using this approach, adding in a keycloak is possible without breaking changes at a later point, as long as I keep the Google Sign In.
|
||||
|
||||
|
||||
### Email
|
||||
|
||||
For Email verification, etc. a mail server is needed, that can send a whole lot of mails. Aditionally, a mail account is needed for incoming mails. I thought about self hosting, but unfortunatly this is a hastle to maintain. Not only you have to setup a mail server, which is not as easy as it sounds, you also have to "register" your mail server for diffrent providers. Otherwise you are not able to send and receive emails. Thus, the first external service is needed.
|
||||
|
||||
In order to not vendor lock in, I decided to use an SMTP relay in favor of a vendor specific API. You are free to choose a transactional mail provider. I chose brevo.com. They have a generous free tier of 300 mails per day. You can either upgrade to a monthly plan 10$ for 20k mails or buy credits for 30$ for 5k mails. Most provider provide 100 mails / day for free.
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"me-fit/middleware"
|
||||
"me-fit/service"
|
||||
"me-fit/utils"
|
||||
|
||||
"database/sql"
|
||||
"net/http"
|
||||
@@ -13,6 +14,10 @@ func getHandler(db *sql.DB) http.Handler {
|
||||
|
||||
router.HandleFunc("/", service.HandleIndexAnd404(db))
|
||||
|
||||
router.HandleFunc("/mail", func(w http.ResponseWriter, r *http.Request) {
|
||||
utils.SendWelcomeMail("timwundenberg@outlook.de")
|
||||
})
|
||||
|
||||
// Serve static files (CSS, JS and images)
|
||||
router.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static/"))))
|
||||
|
||||
|
||||
31
main.go
31
main.go
@@ -20,6 +20,7 @@ func main() {
|
||||
if err != nil {
|
||||
log.Fatal("Error loading .env file")
|
||||
}
|
||||
utils.MustInitEnv()
|
||||
|
||||
db, err := sql.Open("sqlite3", "./data.db")
|
||||
if err != nil {
|
||||
@@ -27,19 +28,9 @@ func main() {
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
utils.RunMigrations(db)
|
||||
utils.MustRunMigrations(db)
|
||||
|
||||
var prometheusServer = http.Server{
|
||||
Addr: ":8081",
|
||||
Handler: promhttp.Handler(),
|
||||
}
|
||||
go func() {
|
||||
slog.Info("Starting prometheus server on " + prometheusServer.Addr)
|
||||
err := prometheusServer.ListenAndServe()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
startPrometheus()
|
||||
|
||||
var server = http.Server{
|
||||
Addr: ":8080",
|
||||
@@ -52,3 +43,19 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func startPrometheus() {
|
||||
|
||||
var prometheusServer = http.Server{
|
||||
Addr: ":8081",
|
||||
Handler: promhttp.Handler(),
|
||||
}
|
||||
|
||||
go func() {
|
||||
slog.Info("Starting prometheus server on " + prometheusServer.Addr)
|
||||
err := prometheusServer.ListenAndServe()
|
||||
if err != nil {
|
||||
log.Fatal("Could not start prometheus server: ", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"log"
|
||||
"log/slog"
|
||||
"me-fit/utils"
|
||||
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
func EnableCors(next http.Handler) http.Handler {
|
||||
var base_url = os.Getenv("BASE_URL")
|
||||
if base_url == "" {
|
||||
log.Fatal("BASE_URL is not set")
|
||||
}
|
||||
slog.Info("BASE_URL is " + base_url)
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Access-Control-Allow-Origin", base_url)
|
||||
w.Header().Set("Access-Control-Allow-Origin", utils.BaseUrl)
|
||||
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, DELETE")
|
||||
|
||||
if r.Method == "OPTIONS" {
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
_ "github.com/golang-migrate/migrate/v4/source/file"
|
||||
)
|
||||
|
||||
func RunMigrations(db *sql.DB) {
|
||||
func MustRunMigrations(db *sql.DB) {
|
||||
driver, err := sqlite3.WithInstance(db, &sqlite3.Config{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
||||
57
utils/env.go
Normal file
57
utils/env.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"log"
|
||||
"log/slog"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
SmtpHost string
|
||||
SmtpPort string
|
||||
SmtpUser string
|
||||
SmtpPass string
|
||||
SmtpFromMail string
|
||||
SmtpFromName string
|
||||
BaseUrl string
|
||||
)
|
||||
|
||||
func MustInitEnv() {
|
||||
SmtpHost = os.Getenv("SMTP_HOST")
|
||||
SmtpPort = os.Getenv("SMTP_PORT")
|
||||
SmtpUser = os.Getenv("SMTP_USER")
|
||||
SmtpPass = os.Getenv("SMTP_PASS")
|
||||
SmtpFromMail = os.Getenv("SMTP_FROM_MAIL")
|
||||
SmtpFromName = os.Getenv("SMTP_FROM_NAME")
|
||||
BaseUrl = os.Getenv("BASE_URL")
|
||||
|
||||
if SmtpHost == "" {
|
||||
log.Fatal("SMTP_HOST must be set")
|
||||
}
|
||||
if SmtpPort == "" {
|
||||
log.Fatal("SMTP_PORT must be set")
|
||||
}
|
||||
if SmtpUser == "" {
|
||||
log.Fatal("SMTP_USER must be set")
|
||||
}
|
||||
if SmtpPass == "" {
|
||||
log.Fatal("SMTP_PASS must be set")
|
||||
}
|
||||
if SmtpFromMail == "" {
|
||||
log.Fatal("SMTP_FROM_MAIL must be set")
|
||||
}
|
||||
if SmtpFromName == "" {
|
||||
log.Fatal("SMTP_FROM_NAME must be set")
|
||||
}
|
||||
if BaseUrl == "" {
|
||||
log.Fatal("BASE_URL must be set")
|
||||
}
|
||||
|
||||
slog.Info("BASE_URL is " + BaseUrl)
|
||||
slog.Info("SMTP_HOST is " + SmtpHost)
|
||||
slog.Info("SMTP_PORT is " + SmtpPort)
|
||||
slog.Info("SMTP_USER is " + SmtpUser)
|
||||
slog.Info("SMTP_PASS is " + SmtpPass)
|
||||
slog.Info("SMTP_FROM_MAIL is " + SmtpFromMail)
|
||||
slog.Info("SMTP_FROM_NAME is " + SmtpFromName)
|
||||
}
|
||||
19
utils/mail.go
Normal file
19
utils/mail.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"net/smtp"
|
||||
)
|
||||
|
||||
func SendWelcomeMail(to string) {
|
||||
|
||||
auth := smtp.PlainAuth("", SmtpUser, SmtpPass, SmtpHost)
|
||||
|
||||
msg := "From: " + SmtpFromName + " <" + SmtpFromMail + ">\nTo: " + to + "\nSubject: Welcome to me-fit\n\nWelcome to me-fit!"
|
||||
|
||||
err := smtp.SendMail(SmtpHost+":"+SmtpPort, auth, SmtpFromMail, []string{to}, []byte(msg))
|
||||
if err != nil {
|
||||
slog.Error("Could not send mail: " + err.Error())
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user