Class AccountNotices
AccountMails - (CC-SERVERADMIN-SIGNOUT-DEVICES, the owner's rulings of 2026-10-13 05:01 and AM-1 of 05:09): every change to a user's account settings is told to the user by mail, in the user's language (English, French or Swedish), with what changed, when, from which client address and approximate place, by whom, and what to do if it was not the user. No mail carries a secret, a token or a code.The notices that existed before (SD-D-3, ruled 2026-10-13 21:39). The notice of a password an administrator set (AccountNotices.Kind.PASSWORD_SET) and the notice to the OLD address of a changed address (AccountNotices.Kind.EMAIL_CHANGED, by the user's confirmation link or by an administrator) go through here as well (CC-FIX-SERVERADMIN-SD18-SD3); before, they were English-only texts of AccountMails without when, where and by whom. Both are critical: they were mailed whatever the setting before, and still are.
The opt-out (AM-1). A user turns the notices off in Sign-in & security (setWanted(Connection, BasicUserInfo, boolean): the detail "IZS-AccountNotices" is "off"; absent, the notices are on). The security-critical notices - a changed, reset or administrator-set password, a changed address, a removed second factor or passkey, the reset of the sign-in methods, and the change of this setting itself - are sent whatever the setting (AccountNotices.Kind.critical): an attacker who takes an account over turns the notices off first.
Nothing here throws to its caller: a notice that cannot be mailed is logged at WARNING, once, with the address masked (EmailAddressForm.masked(String)), and the change it is about stands. One INFO line per notice names its kind and the user: Account notice <KIND> for user "<name>": queued, or why it was not mailed.
The placeholder address (MDV-D-34, CC-FIX-MLS-REHEARSAL-FINDINGS). The administrator the server's database is created with carries the address default@iizi.server.administrator (AdministratorAccess.SEEDED_EMAIL_DOMAIN), where no mailbox is: a notice to such an address, or to a text that is not an address, is dropped with one INFO line (AccountNotices.Outcome.PLACEHOLDER_ADDRESS) and never queued. The MLS rehearsal of 2026-10-23 queued three such notices (SECOND_FACTOR_ADDED, DEVICE_TRUSTED, PASSWORD_CHANGED) to the placeholder, to bounce at the relay.
- Author:
- Christopher Mindus
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic enumWho made the change.static final recordWhere the change was made from: the client address and the approximate place, each null when unknown, the base of the links the mail carries - the origin the client session reached the server by, else the server's configured external URL (MailLinkBase, R-145), null when neither is known - and the device line the server has for the session (ClientDeviceName), null when unknown.static enumWhat changed.static enumWhat became of a notice.Field Summary
FieldsModifier and TypeFieldDescriptionstatic final StringThe detail ofSECOND_FACTOR_REMOVEDfor the authenticator app of a user whose passkey is the second factor that is left, with the recovery codes (CC-FIX-SIGNIN-2FA-CHOICE).static final StringThe value of the detail that turns the notices off; any other value or no detail is on.static final StringThe detail ofSECOND_FACTOR_ADDEDandSECOND_FACTOR_REMOVEDfor a passkey that is the second factor (CC-FIX-SIGNIN-2FA-CHOICE): the text names the passkey, not an app.Method Summary
Modifier and TypeMethodDescriptionstatic Stringbody(AccountNotices.Kind kind, UserInfoBase user, AccountNotices.By by, AccountNotices.Context context, long when, String extra, String lang) The text of a notice: what changed, when, from where, by whom, and what to do if it was not the user.static AccountNotices.ContextcontextOf(IClientSessionGyro clientGyro) Where a change was made from: the client address of the session, resolved as the sign-in throttle and the session geolocation resolve it (the connection's address, unless it is a trusted proxy's and the headers name the client), and the place the server's region location provider knows for it, withinPLACE_LOOKUP_MS.static booleanisWanted(UserInfoBase user) Checks if the user wants the notices that are not critical: the detail "IZS-AccountNotices" is absent or not "off".static AccountNotices.Outcomenotify(AccountNotices.Kind kind, IClientSessionGyro clientGyro, UserInfoBase user, AccountNotices.By by, String extra) Tells a user of a change from the server: the server's default mail sender, the mail queued, the context from the client session the change was made in.static AccountNotices.Outcomesend(AccountNotices.Kind kind, UserInfoBase user, AccountNotices.By by, AccountNotices.Context context, long when, String extra, MailSender sender, AccountEmailChange.IMailStep deliver) Tells a user of a change: the mail is composed in the user's language and handed to the delivery step, unless the user turned the notices off and the kind is not critical (AM-1).static AccountNotices.OutcomesendTo(String to, AccountNotices.Kind kind, UserInfoBase user, AccountNotices.By by, AccountNotices.Context context, long when, String extra, MailSender sender, AccountEmailChange.IMailStep deliver) Tells a user of a change at a given address: assend(AccountNotices.Kind, UserInfoBase, AccountNotices.By, AccountNotices.Context, long, String, MailSender, AccountEmailChange.IMailStep), but the mail goes totorather than to the user's registered address - the OLD address of a changed address (AccountNotices.Kind.EMAIL_CHANGED), which the user no longer has once the change is written.static voidsetWanted(Connection conn, BasicUserInfo user, boolean wanted) Turns the notices on or off for a user, inside the caller's transaction: the detail is deleted for on, set to "off" for off.static Stringsubject(AccountNotices.Kind kind, String lang) The subject of a notice.
Field Details
OFF
The value of the detail that turns the notices off; any other value or no detail is on.- See Also:
PASSKEY_FACTOR
The detail ofSECOND_FACTOR_ADDEDandSECOND_FACTOR_REMOVEDfor a passkey that is the second factor (CC-FIX-SIGNIN-2FA-CHOICE): the text names the passkey, not an app. No detail is the authenticator app, as before.- See Also:
APP_REMOVED_PASSKEY_LEFT
The detail ofSECOND_FACTOR_REMOVEDfor the authenticator app of a user whose passkey is the second factor that is left, with the recovery codes (CC-FIX-SIGNIN-2FA-CHOICE).- See Also:
Method Details
isWanted
Checks if the user wants the notices that are not critical: the detail "IZS-AccountNotices" is absent or not "off".- Parameters:
user- The user.- Returns:
- true when the user has not turned the notices off.
setWanted
public static void setWanted(Connection conn, BasicUserInfo user, boolean wanted) throws SQLException Turns the notices on or off for a user, inside the caller's transaction: the detail is deleted for on, set to "off" for off. Nothing is committed here, and no notice is sent here: the caller tells the user.- Parameters:
conn- The connection of the caller's transaction.user- The user.wanted- true for on, false for off.- Throws:
SQLException- For SQL errors.
contextOf
Where a change was made from: the client address of the session, resolved as the sign-in throttle and the session geolocation resolve it (the connection's address, unless it is a trusted proxy's and the headers name the client), and the place the server's region location provider knows for it, withinPLACE_LOOKUP_MS. A private or local address is not looked up. The base of the mailed links is the session's origin, else the configured external URL (MailLinkBase); the device line is what the client says it is (ClientDeviceName). Never throws.- Parameters:
clientGyro- The client session, null for none.- Returns:
- The context,
AccountNotices.Context.NONEwhen nothing is known.
notify
public static AccountNotices.Outcome notify(AccountNotices.Kind kind, IClientSessionGyro clientGyro, UserInfoBase user, AccountNotices.By by, String extra) Tells a user of a change from the server: the server's default mail sender, the mail queued, the context from the client session the change was made in. Never throws; the outcome is logged (one INFO line, or a WARNING when the mail could not go).- Parameters:
kind- What changed.clientGyro- The client session the change was made in, null for none.user- The user whose account changed.by- Who made the change.extra- A detail of the change for the text (a passkey's nickname, a count, "on"/"off"), null for none; never a secret.- Returns:
- What became of the notice.
send
public static AccountNotices.Outcome send(AccountNotices.Kind kind, UserInfoBase user, AccountNotices.By by, AccountNotices.Context context, long when, String extra, MailSender sender, AccountEmailChange.IMailStep deliver) Tells a user of a change: the mail is composed in the user's language and handed to the delivery step, unless the user turned the notices off and the kind is not critical (AM-1). Never throws; the outcome is logged (one INFO line, or a WARNING when the mail could not go).- Parameters:
kind- What changed.user- The user whose account changed.by- Who made the change.context- Where the change was made from,AccountNotices.Context.NONEwhen unknown.when- When, milliseconds since the epoch.extra- A detail of the change for the text, null for none; never a secret.sender- The mail sender, null for none configured.deliver- The delivery step.- Returns:
- What became of the notice.
- Throws:
NullPointerException- If the kind, the user, the context or the delivery step is null.
sendTo
public static AccountNotices.Outcome sendTo(String to, AccountNotices.Kind kind, UserInfoBase user, AccountNotices.By by, AccountNotices.Context context, long when, String extra, MailSender sender, AccountEmailChange.IMailStep deliver) Tells a user of a change at a given address: assend(AccountNotices.Kind, UserInfoBase, AccountNotices.By, AccountNotices.Context, long, String, MailSender, AccountEmailChange.IMailStep), but the mail goes totorather than to the user's registered address - the OLD address of a changed address (AccountNotices.Kind.EMAIL_CHANGED), which the user no longer has once the change is written.- Parameters:
to- The address the mail goes to, null or blank for none.kind- What changed.user- The user whose account changed.by- Who made the change.context- Where the change was made from,AccountNotices.Context.NONEwhen unknown.when- When, milliseconds since the epoch.extra- A detail of the change for the text, null for none; never a secret.sender- The mail sender, null for none configured.deliver- The delivery step.- Returns:
- What became of the notice.
- Throws:
NullPointerException- If the kind, the user, the context or the delivery step is null.
subject
The subject of a notice.- Parameters:
kind- What changed.lang- The language, "en", "fr" or "sv".- Returns:
- The subject.
body
public static String body(AccountNotices.Kind kind, UserInfoBase user, AccountNotices.By by, AccountNotices.Context context, long when, String extra, String lang) The text of a notice: what changed, when, from where, by whom, and what to do if it was not the user. No secret.- Parameters:
kind- What changed.user- The user.by- Who made the change.context- Where from.when- When, milliseconds since the epoch.extra- A detail of the change, null for none.lang- The language, "en", "fr" or "sv".- Returns:
- The plain text.