package email
import (
"bytes"
"fmt"
"html/template"
"imageboard/config"
"imageboard/database"
"imageboard/models"
"net/smtp"
"regexp"
)
func extractEmailAddress(from string) string {
re := regexp.MustCompile(`<([^>]+)>`)
matches := re.FindStringSubmatch(from)
if len(matches) == 2 {
return matches[1]
}
return from
}
func SendMail(to, subject, body string) error {
var auth smtp.Auth
if config.SMTP.Username != "" {
auth = smtp.PlainAuth("", config.SMTP.Username, config.SMTP.Password, config.SMTP.Host)
} else {
auth = nil
}
fromHeader := config.SMTP.From
fromAddress := extractEmailAddress(config.SMTP.From)
msg := fmt.Sprintf("From: %s\r\nTo: %s\r\nSubject: %s\r\nMIME-Version: 1.0\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n%s",
fromHeader, to, subject, body)
addr := fmt.Sprintf("%s:%d", config.SMTP.Host, config.SMTP.Port)
return smtp.SendMail(addr, auth, fromAddress, []string{to}, []byte(msg))
}
func SendVerificationEmail(user *models.User) error {
token, err := database.GenerateEmailToken(int(user.ID), config.EmailTokenTypeVerification)
if err != nil {
return fmt.Errorf("failed to generate verification token: %w", err)
}
tmpl, err := template.ParseFiles("templates/email/verification.html")
if err != nil {
return fmt.Errorf("failed to parse email template: %w", err)
}
verificationLink := fmt.Sprintf("%s%s?token=%s", config.Server.AppBaseURL, config.URL_VERIFY_EMAIL, token.Token)
data := struct {
Username string
Appname string
Link string
}{
Username: user.Username,
Appname: config.Server.AppName,
Link: verificationLink,
}
var body bytes.Buffer
if err := tmpl.Execute(&body, data); err != nil {
return fmt.Errorf("failed to execute email template: %w", err)
}
subject := fmt.Sprintf("Verify your email for %s", config.Server.AppName)
return SendMail(user.Email, subject, body.String())
}
func SendForgotUsernameEmail(users *[]models.User) error {
tmpl, err := template.ParseFiles("templates/email/forgot_username.html")
if err != nil {
return fmt.Errorf("failed to parse email template: %w", err)
}
resetLink := fmt.Sprintf("%s%s?mode=password", config.Server.AppBaseURL, config.URL_FORGOT_PASSWORD)
var usernames string
for i, user := range *users {
usernames += user.Username
if i < len(*users)-1 {
usernames += ", "
}
}
data := struct {
Username string
Appname string
Link string
}{
Username: usernames,
Appname: config.Server.AppName,
Link: resetLink,
}
var body bytes.Buffer
if err := tmpl.Execute(&body, data); err != nil {
return fmt.Errorf("failed to execute email template: %w", err)
}
subject := fmt.Sprintf("Your username for %s", config.Server.AppName)
return SendMail((*users)[0].Email, subject, body.String())
}
// func SendPasswordResetEmail(user *models.User) error {
// token, err := user.GenerateToken(database.DB, models.EmailTokenTypePasswordReset)
// if err != nil {
// return fmt.Errorf("failed to generate password reset token: %w", err)
// }
// tmpl, err := template.ParseFiles("templates/email/password_reset.html")
// if err != nil {
// return fmt.Errorf("failed to parse email template: %w", err)
// }
// resetLink := fmt.Sprintf("%s/account/reset-password?token=%s", config.Server.AppBaseURL, token.Token)
// data := struct {
// Username string
// Link string
// }{
// Username: user.Username,
// Link: resetLink,
// }
// var body bytes.Buffer
// if err := tmpl.Execute(&body, data); err != nil {
// return fmt.Errorf("failed to execute email template: %w", err)
// }
// subject := fmt.Sprintf("Password reset for %s", config.Server.AppName)
// return SendMail(user.Email, subject, body.String())
// }
// func SendEmailChangeConfirmation(user *models.User, newEmail string) error {
// token, err := user.GenerateToken(database.DB, models.EmailTokenTypeChangeEmail)
// if err != nil {
// return fmt.Errorf("failed to generate email change token: %w", err)
// }
// tmpl, err := template.ParseFiles("templates/email/email_change.html")
// if err != nil {
// return fmt.Errorf("failed to parse email template: %w", err)
// }
// confirmLink := fmt.Sprintf("%s/account/confirm-email-change?token=%s&email=%s", config.Server.AppBaseURL, token.Token, newEmail)
// data := struct {
// Username string
// NewEmail string
// Link string
// }{
// Username: user.Username,
// NewEmail: newEmail,
// Link: confirmLink,
// }
// var body bytes.Buffer
// if err := tmpl.Execute(&body, data); err != nil {
// return fmt.Errorf("failed to execute email template: %w", err)
// }
// subject := fmt.Sprintf("Confirm email change for %s", config.Server.AppName)
// return SendMail(newEmail, subject, body.String())
// }