Email delivery tweaks

This commit is contained in:
Noah Petherbridge 2024-09-09 20:52:53 -07:00
parent 276eddfd8e
commit 463253dbb5
5 changed files with 56 additions and 37 deletions

View File

@ -50,6 +50,7 @@ const (
ResetPasswordRedisKey = "reset-password/%s" ResetPasswordRedisKey = "reset-password/%s"
ChangeEmailRedisKey = "change-email/%s" ChangeEmailRedisKey = "change-email/%s"
SignupTokenExpires = 24 * time.Hour // used for all tokens so far SignupTokenExpires = 24 * time.Hour // used for all tokens so far
EmailDebounceExpires = 24 * time.Hour // how to rate limit duplicate mail being sent
// Rate limits // Rate limits
RateLimitRedisKey = "rate-limit/%s/%s" // namespace, id RateLimitRedisKey = "rate-limit/%s/%s" // namespace, id

View File

@ -139,24 +139,29 @@ func Signup() http.HandlerFunc {
} }
// Already an account? // Already an account?
if _, err := models.FindUser(email); err == nil { if user, err := models.FindUser(email); err == nil {
// We don't want to admit that the email already is registered, so send an email to the // We don't want to admit that the email already is registered, so send an email to the
// address in case the user legitimately forgot, but flash the regular success message. // address in case the user legitimately forgot, but flash the regular success message.
if err := mail.LockSending("signup", email, config.SignupTokenExpires); err == nil { if user.IsBanned() {
err := mail.Send(mail.Message{ log.Error("Do not send signup e-mail to %s: user is banned", email)
To: email,
Subject: "You already have a nonshy account",
Template: "email/already_signed_up.html",
Data: map[string]interface{}{
"Title": config.Title,
"URL": config.Current.BaseURL + "/forgot-password",
},
})
if err != nil {
session.FlashError(w, r, "Error sending an email: %s", err)
}
} else { } else {
log.Error("LockSending: signup e-mail is not sent to %s: one was sent recently", email) if err := mail.LockSending("signup", email, config.EmailDebounceExpires); err == nil {
err := mail.Send(mail.Message{
To: email,
Subject: "You already have a nonshy account",
Template: "email/already_signed_up.html",
Data: map[string]interface{}{
"Title": config.Title,
"URL": config.Current.BaseURL + "/forgot-password",
},
})
if err != nil {
session.FlashError(w, r, "Error sending an email: %s", err)
}
} else {
log.Error("LockSending: signup e-mail is not sent to %s: one was sent recently", email)
}
} }
session.Flash(w, r, "We have sent an e-mail to %s with a link to continue signing up your account. Please go and check your e-mail.", email) session.Flash(w, r, "We have sent an e-mail to %s with a link to continue signing up your account. Please go and check your e-mail.", email)

View File

@ -434,17 +434,21 @@ func AdminCertification() http.HandlerFunc {
} }
// Notify the user via email. // Notify the user via email.
if err := mail.Send(mail.Message{ if err := mail.LockSending("cert_rejected", user.Email, config.EmailDebounceExpires); err == nil {
To: user.Email, if err := mail.Send(mail.Message{
Subject: "Your certification photo has been rejected", To: user.Email,
Template: "email/certification_rejected.html", Subject: "Your certification photo has been denied",
Data: map[string]interface{}{ Template: "email/certification_rejected.html",
"Username": user.Username, Data: map[string]interface{}{
"AdminComment": comment, "Username": user.Username,
"URL": config.Current.BaseURL + "/photo/certification", "AdminComment": comment,
}, "URL": config.Current.BaseURL + "/photo/certification",
}); err != nil { },
session.FlashError(w, r, "Note: failed to email user about the rejection: %s", err) }); err != nil {
session.FlashError(w, r, "Note: failed to email user about the rejection: %s", err)
}
} else {
log.Error("LockSending: cert_rejected e-mail is not sent to %s: one was sent recently", user.Email)
} }
} }
@ -503,16 +507,20 @@ func AdminCertification() http.HandlerFunc {
} }
// Notify the user via email. // Notify the user via email.
if err := mail.Send(mail.Message{ if err := mail.LockSending("cert_approved", user.Email, config.EmailDebounceExpires); err == nil {
To: user.Email, if err := mail.Send(mail.Message{
Subject: "Your certification photo has been approved!", To: user.Email,
Template: "email/certification_approved.html", Subject: "Your certification photo has been approved!",
Data: map[string]interface{}{ Template: "email/certification_approved.html",
"Username": user.Username, Data: map[string]interface{}{
"URL": config.Current.BaseURL, "Username": user.Username,
}, "URL": config.Current.BaseURL,
}); err != nil { },
session.FlashError(w, r, "Note: failed to email user about the approval: %s", err) }); err != nil {
session.FlashError(w, r, "Note: failed to email user about the approval: %s", err)
}
} else {
log.Error("LockSending: cert_approved e-mail is not sent to %s: one was sent recently", user.Email)
} }
// Log the change. // Log the change.

View File

@ -226,6 +226,11 @@ func IsValidUsername(username string) error {
return nil return nil
} }
// IsBanned returns if the user account is banned.
func (u *User) IsBanned() bool {
return u.Status == UserStatusBanned
}
// IsShyFrom tells whether the user is shy from the perspective of the other user. // IsShyFrom tells whether the user is shy from the perspective of the other user.
// //
// That is, depending on our profile visibility and friendship status. // That is, depending on our profile visibility and friendship status.

View File

@ -3,7 +3,7 @@
<body bakground="#ffffff" color="#000000" link="#0000FF" vlink="#990099" alink="#FF0000"> <body bakground="#ffffff" color="#000000" link="#0000FF" vlink="#990099" alink="#FF0000">
<basefont face="Arial,Helvetica,sans-serif" size="3" color="#000000"></basefont> <basefont face="Arial,Helvetica,sans-serif" size="3" color="#000000"></basefont>
<h1>Your certification photo has been rejected</h1> <h1>Your certification photo has been denied</h1>
<p>Dear {{.Data.Username}},</p> <p>Dear {{.Data.Username}},</p>