package emailApi import ( "fmt" "git.stuve.uni-ulm.de/stuve-it/stuve-it-backend/logger" "github.com/microcosm-cc/bluemonday" "github.com/pocketbase/pocketbase" "github.com/pocketbase/pocketbase/core" "github.com/pocketbase/pocketbase/models" "github.com/pocketbase/pocketbase/tools/mailer" "github.com/pocketbase/pocketbase/tools/template" "net/mail" "time" ) // sendEmailToUser sends an email notification to a recipient of the email record func sendEmailToUser(app *pocketbase.PocketBase, registry *template.Registry, recipient *models.Record, sender *models.Record, emailRecord *models.Record) error { // check if recipient and message are set and recipient is not the sender if recipient == nil || emailRecord == nil || sender == nil { return fmt.Errorf("unable to send email to recipient: recipient, sender or email record is nil") } // sanitize email content policy := bluemonday.UGCPolicy() content := emailRecord.GetString("content") safeContent := policy.Sanitize(content) // get recipient and sender email recipientEmail := recipient.GetString("email") senderEmail := sender.GetString("email") // get email subject subject := "[StuVe IT] " + emailRecord.GetString("subject") // render email template html, err := registry.LoadFiles( "html/blankEmail.html", ).Render(map[string]any{ "APP_URL": app.Settings().Meta.AppUrl, "SENDER_SN": sender.GetString("sn"), "SENDER_GIVENNAME": sender.GetString("givenName"), "SENDER_EMAIL": senderEmail, "CONTENT": safeContent, "SUBJECT": subject, }) if err != nil { return fmt.Errorf("error rendering email template for user with id '%s': %v", recipient.Id, err) } // set reply-to header headers := make(map[string]string) headers["Reply-To"] = senderEmail // send email email := &mailer.Message{ From: mail.Address{ Address: app.Settings().Meta.SenderAddress, Name: app.Settings().Meta.SenderName, }, To: []mail.Address{{Address: recipientEmail}}, Subject: subject, HTML: html, Headers: headers, } if err := app.NewMailClient().Send(email); err != nil { return fmt.Errorf("error sending email to user with id '%s': %v", recipient.Id, err) } return nil } // sendEmails sends an email notification to the recipients of the email record@ func sendEmails(app *pocketbase.PocketBase, emailRecord *models.Record) { registry := template.NewRegistry() // expand the createdMessageRecord to get recipient user and send email notification if recipient is set if errs := app.Dao().ExpandRecord(emailRecord, []string{"recipients", "sender"}, nil); len(errs) > 0 { // return new error with all errors logger.LogErrorF("Error expanding created email record: %v", errs) emailRecord.Set("errors", fmt.Sprintf("The email was not sent to anyone due to an error.")) return } // get sender and recipients sender := emailRecord.ExpandedOne("sender") recipients := emailRecord.ExpandedAll("recipients") // this is the list of user ids that the email was sent to sendToIds := make([]string, 0) // send email to each recipient for _, recipient := range recipients { // send email to user err := sendEmailToUser(app, registry, recipient, sender, emailRecord) // check if there was an error sending the email if err != nil { logger.LogErrorF("%v", err) continue } // add recipient id to sendToIds sendToIds = append(sendToIds, recipient.Id) // update email sentTo field, this will be overwritten for each recipient // we update it for every iteration to provide live feedback on the frontend emailRecord.Set("sentTo", sendToIds) // save email record if err := app.Dao().SaveRecord(emailRecord); err != nil { logger.LogErrorF("Error saving email record: %v", err) } } // mark email as sent emailRecord.Set("sentTo", sendToIds) emailRecord.Set("sentAt", time.Now()) // save email record if err := app.Dao().SaveRecord(emailRecord); err != nil { logger.LogErrorF("Error saving email record: %v", err) } return } // InitEmailApi initializes the email notifier // // the function sends an email notification after it was created func InitEmailApi(app *pocketbase.PocketBase, _ *core.ServeEvent) error { logger.LogInfoF("Adding email notifier") app.OnModelAfterCreate("emails").Add(func(e *core.ModelEvent) error { // get created message record createdEmailRecord, err := app.Dao().FindRecordById("emails", e.Model.GetId()) if err != nil { return err } go sendEmails(app, createdEmailRecord) return nil }) return nil }