Class AccountNotices

java.lang.Object
com.iizix.server.user.AccountNotices

public final class AccountNotices extends Object
The notice mails about changes to a user's account that are not the verification mail of an address or the confirmation link of a change of address - those are 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
  • Field Details

    • OFF

      public static final String OFF
      The value of the detail that turns the notices off; any other value or no detail is on.
      See Also:
    • PASSKEY_FACTOR

      public static final String PASSKEY_FACTOR
      The detail of SECOND_FACTOR_ADDED and SECOND_FACTOR_REMOVED for 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

      public static final String APP_REMOVED_PASSKEY_LEFT
      The detail of SECOND_FACTOR_REMOVED for 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

      public static boolean isWanted(UserInfoBase user)
      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

      public static AccountNotices.Context contextOf(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, within PLACE_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.NONE when 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.NONE when 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: as send(AccountNotices.Kind, UserInfoBase, AccountNotices.By, AccountNotices.Context, long, String, MailSender, AccountEmailChange.IMailStep), but the mail goes to to rather 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.NONE when 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

      public static String subject(AccountNotices.Kind kind, String lang)
      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.