add mail
Ezt a generátort akkor éri meg elővenni, amikor egy modulnak közvetlenül egy címre kell emailt küldenie, recipient-fogalom nélkül: egy contact-form visszaigazolás, egy számla, egy jelszó-visszaállító link.
go tool gpsystem add mail <modul> <név>
Egy notifiert hoz létre az internal/modules/<modul>/mail/<név>.go-ban: egy payload structot, egy <Név>Notifier-t, ami egy injektált mail.Mailer-t köt össze a modul saját sablonjaival, plusz a templates/<név>.html.tmpl + templates/<név>.txt.tmpl fájlokat. A projekt első mail-notifierénél (bármelyik modulban) bedrótozza a közös transzportot is minden belépési pontba. Idempotens: egy második notifier, akár ugyanabban, akár másik modulban, újrahasználja a bekötést.
go tool gpsystem add mail contact contactNotification
Miért ez a szétválasztás
A mail-tartalom (payload, sablonok, subject) üzleti tartalom, ami azé a moduléé, amelyik a use case-t birtokolja; az SMTP-transzport infrastruktúra, pont mint az adatbázis-driver, ezért egyszer van centralizálva. Ez ugyanaz a közös kód döntési létra, amit a kit mindenhol követ; lásd a Projektstruktúra oldal teljes indoklását és a mail oldal kidolgozott példáját.
Mit generál
package mail
//go:embed templates/contactnotification.html.tmpl templates/contactnotification.txt.tmpl
var contactNotificationTemplatesFS embed.FS
type ContactNotification struct {
}
type ContactNotificationNotifier struct{ mailer kitmail.Mailer }
func NewContactNotificationNotifier(m kitmail.Mailer) *ContactNotificationNotifier {
return &ContactNotificationNotifier{mailer: m}
}
func (n *ContactNotificationNotifier) Notify(ctx context.Context, to string, p ContactNotification) error {
msg := kitmail.NewMessage().
WithTo(to).
WithSubject("TODO: subject for ContactNotification").
WithBody(kitmail.Template(contactNotificationTemplatesFS, "templates/contactnotification.html.tmpl", p).
WithTextTemplate("templates/contactnotification.txt.tmpl"))
return n.mailer.Send(ctx, msg)
}
Plusz egy memory-mailer teszt (contactnotification_test.go) és két kitöltendő placeholder sablon. A payload struct üresen indul, ugyanúgy, ahogy az add event is üres event structot generál: add hozzá a sablonjaidnak szükséges mezőket.
A projekt első notifierénél:
Mail smtp.Config `envPrefix:"MAIL_"`
mailer := smtp.MustNewIfConfigured(ctx, cfg.Mail)
// ...
deps := contact.Dependencies{
// ...
Mailer: mailer,
// gpsystem:dependencies-init
}
type Dependencies struct {
// ...
Mailer mail.Mailer
// gpsystem:dependencies
}
A mailer belépési pontonként egyszer konstruálódik, és minden notifiert tartalmazó modul osztozik rajta, ugyanaz a minta, mint a közös adatbázis-poolnál. Az smtp.MustNewIfConfigured valódi SMTP-klienst épít, ha a MAIL_HOST be van állítva, vagy mail.NewDiscard()-ot, ha üres, így a dev környezetek mail-szerver nélkül is futnak. Lásd a Mail oldalt a teljes MAIL_* referenciáért.
Küldés
Semmi nem hívja automatikusan a notifiert: kösd be egy service-ből (szinkron mail, pl. jelszó-visszaállítás) vagy egy listenerből (aszinkron, add event / add listener révén):
notifier := contactmail.NewContactNotificationNotifier(deps.Mailer)
return notifier.Notify(ctx, recipientAddress, contactmail.ContactNotification{ /* ... */ })
Anchor-kommentek
Az add db-hez hasonlóan az add mail a gpsystem:pools, gpsystem:dependencies-init/gpsystem:deps-init(<modul>), gpsystem:dependencies és gpsystem:config anchoroknál ír. Ha egy modulból hiányzik valamelyik anchor-komment, a parancs megáll, és kiírja a pontos, beillesztendő blokkot a helyes pozícióval együtt.
Melyik parancsot mikor
Címre menő tartalomhoz, recipient-fogalom nélkül ezt a parancsot (fent). Recipiensnek szóló, akár több csatornás tartalomhoz (database-inbox, élő push) az add notification-t helyette. A kettő összeadódik: egy notification ToMail-je ugyanazokat a buildereket használja, mint amiket fent láttál.