Implement mailer and add welcome email for POP account

This commit is contained in:
William Bouzourène 2026-05-05 18:58:40 +02:00
parent a6b926c9bf
commit b582b10360
Signed by: bouzoure
GPG key ID: 423440D735B56BE2
10 changed files with 170 additions and 3 deletions

View file

@ -5,4 +5,11 @@ APP_LISTEN_PORT=3000
APP_BEHIND_PROXY=false
DATABASE_DSN="host=localhost user=camarades password=camarades dbname=camarades port=5432 sslmode=disable TimeZone=Europe/Zurich"
SESSIONS_LOCATION=./sessions.db
AUTHELIA_USERS_LOCATION=./users.yml
AUTHELIA_USERS_LOCATION=./users.yml
AUTHELIA_RESET_URL=https://login.popvaud.ch/reset-password/step1
MAIL_HOST=mail.infomaniak.com
MAIL_PORT=587
MAIL_USERNAME=no-reply@popvaud.ch
MAIL_PASSWORD=very-secure-password
MAIL_FROM_NAME=POP Vaud
MAIL_FROM_ADDRESS=no-reply@popvaud.ch

3
go.mod
View file

@ -1,6 +1,6 @@
module git.readonly.ch/bouzoure/pop-camarades
go 1.25.0
go 1.25.3
require (
github.com/alexedwards/argon2id v1.0.0
@ -16,6 +16,7 @@ require (
github.com/google/uuid v1.6.0
github.com/pquerna/otp v1.5.0
github.com/sethvargo/go-password v0.3.1
github.com/wneessen/go-mail v0.7.2
github.com/yuin/goldmark v1.8.2
go.yaml.in/yaml/v4 v4.0.0-rc.4
golang.org/x/crypto v0.50.0

2
go.sum
View file

@ -222,6 +222,8 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.70.0 h1:LAhMGcWk13QZWm85+eg8ZBNbrq5mnkWFGbHMUJHIdXA=
github.com/valyala/fasthttp v1.70.0/go.mod h1:oDZEHHkJ/Buyklg6uURmYs19442zFSnCIfX3j1FY3pE=
github.com/wneessen/go-mail v0.7.2 h1:xxPnhZ6IZLSgxShebmZ6DPKh1b6OJcoHfzy7UjOkzS8=
github.com/wneessen/go-mail v0.7.2/go.mod h1:+TkW6QP3EVkgTEqHtVmnAE/1MRhmzb8Y9/W3pweuS+k=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=

66
helpers/authelia/mail.go Normal file
View file

@ -0,0 +1,66 @@
package authelia
import (
ht "html/template"
tt "text/template"
"git.readonly.ch/bouzoure/pop-camarades/helpers"
"git.readonly.ch/bouzoure/pop-camarades/models"
)
type InputWelcomeMail struct {
Person models.Person
ResetURL string
}
func SendWelcomeMail(person models.Person) error {
config, err := helpers.GetConfig()
if err != nil {
return err
}
mailer, err := helpers.GetMailer()
if err != nil {
return err
}
msg, err := helpers.NewMessage()
if err != nil {
return err
}
mailsFS, err := helpers.GetEmbeddedFS("mails")
if err != nil {
return err
}
inputValues := InputWelcomeMail{
Person: person,
ResetURL: config.Authelia.ResetURL,
}
tplHTML, err := ht.ParseFS(mailsFS, "mails/welcome.html")
if err != nil {
return err
}
tplTXT, err := tt.ParseFS(mailsFS, "mails/welcome.txt")
if err != nil {
return err
}
msg.Subject("Ton compte POP Vaud")
msg.AddTo(person.Email)
err = msg.SetBodyHTMLTemplate(tplHTML, inputValues)
if err != nil {
return err
}
err = msg.AddAlternativeTextTemplate(tplTXT, inputValues)
if err != nil {
return err
}
return mailer.DialAndSend(msg)
}

View file

@ -101,7 +101,10 @@ func SyncUsers() error {
account.UpdateNeeded = false
if !account.AccountCreated.Valid {
// TODO: send email
err := SendWelcomeMail(account.Person)
if err != nil {
log.Error(err)
}
account.AccountCreated.Scan(time.Now())
}

View file

@ -22,6 +22,15 @@ type Config struct {
}
Authelia struct {
UsersLocation string `env:"AUTHELIA_USERS_LOCATION"`
ResetURL string `env:"AUTHELIA_RESET_URL"`
}
Mail struct {
Host string `env:"MAIL_HOST"`
Port int `env:"MAIL_PORT"`
Username string `env:"MAIL_USERNAME"`
Password string `env:"MAIL_PASSWORD"`
FromName string `env:"MAIL_FROM_NAME"`
FromAddress string `env:"MAIL_FROM_ADDRESS"`
}
}

49
helpers/mailer.go Normal file
View file

@ -0,0 +1,49 @@
package helpers
import (
"github.com/wneessen/go-mail"
)
var mailer *mail.Client
var mailerSet bool
func GetMailer() (*mail.Client, error) {
if mailerSet {
return mailer, nil
}
config, err := GetConfig()
if err != nil {
return mailer, err
}
mailer, err = mail.NewClient(
config.Mail.Host,
mail.WithPort(config.Mail.Port),
mail.WithSMTPAuth(mail.SMTPAuthAutoDiscover),
mail.WithUsername(config.Mail.Username),
mail.WithPassword(config.Mail.Password),
)
if err != nil {
return mailer, err
}
mailerSet = true
return mailer, nil
}
func NewMessage() (*mail.Msg, error) {
msg := mail.NewMsg()
config, err := GetConfig()
if err != nil {
return msg, err
}
msg.FromFormat(
config.Mail.FromName,
config.Mail.FromAddress,
)
return msg, nil
}

19
mails/welcome.html Normal file
View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h1>Ton compte POP Vaud</h1>
<div>
Camarade,<br>
<br>
Ton compte POP Vaud a été créé.<br>
Tu peux désormais réinitialiser ton mot de passe pour t'y connecter.<br>
<br>
Nom d'utilisateur: {{ .Person.Email }}<br>
Mot de passe: <a href="{{ .ResetURL }}">{{ .ResetURL }}</a>
</div>
</body>
</html>

7
mails/welcome.txt Normal file
View file

@ -0,0 +1,7 @@
Camarade,
Ton compte POP Vaud a été créé.
Tu peux désormais réinitialiser ton mot de passe pour t'y connecter.
Nom d'utilisateur: {{ .Person.Email }}
Mot de passe: {{ .ResetURL }}

View file

@ -26,12 +26,16 @@ var embedStatic embed.FS
//go:embed views
var embedViews embed.FS
//go:embed mails
var embedMails embed.FS
func main() {
log := helpers.GetLogger()
// Add embedded filesystems to shared state
helpers.AddEmbeddedFS("static", &embedStatic)
helpers.AddEmbeddedFS("views", &embedViews)
helpers.AddEmbeddedFS("mails", &embedMails)
// Fetch app config
config, err := helpers.GetConfig()