Email owners before inactivity-expiry drops their account or channel

When [expire] warn_days is set and email is configured, the expiry sweep
now emails a heads-up to owners entering the warning window (inactive past
the threshold minus the lead time, but not yet expired) for whom an
address is on file — the founder's address for a channel. It's a chance to
keep the record by simply using it before the deadline.

Each idle spell warns at most once: a new AccountExpiryWarned /
ChannelExpiryWarned event marks the record, and the next activity stamp
clears the mark so a later idle spell warns afresh. The warning email is a
first-class api template (fedserv_api:📧:expiry_warning), alongside
the reset and confirm mails.
This commit is contained in:
Jean Chevronnet 2026-07-14 00:18:43 +00:00
parent 3a6239bbd9
commit 57e104e510
No known key found for this signature in database
7 changed files with 214 additions and 12 deletions

View file

@ -69,6 +69,32 @@ pub fn confirm(brand: &str, accent: &str, logo: &str, account: &str, code: &str)
}
}
// Warn the owner of an account or channel that inactivity will soon expire it.
// `kind` is "account" or "channel", `remaining` a human span ("7 days"). The
// remaining span takes the prominent code slot.
pub fn expiry_warning(brand: &str, accent: &str, logo: &str, kind: &str, name: &str, remaining: &str) -> Mail {
let keep = if kind == "channel" {
"To keep it, have a member join the channel before then. Otherwise it will be removed."
} else {
"To keep it, just identify to it before then. Otherwise it will be removed."
};
Mail {
subject: format!("Your {kind} {name} is about to expire"),
text: format!(
"Your {kind} {name} has been inactive and will expire in {remaining}.\n{keep}\n"
),
html: render(
brand,
accent,
logo,
"About to expire",
&format!("Your {kind} {name} has been inactive and will expire in {remaining}."),
remaining,
keep,
),
}
}
// Escape the few characters that matter inside HTML text so a value can't break
// out of the template.
fn escape(s: &str) -> String {