{
  config,
  lib,
  pkgs,
  ...
}:
let
  inherit (lib) mkOption optionalAttrs types;

  cfg = config.programs.msmtp;

  msmtpAccounts = lib.filter (a: a.enable && a.msmtp.enable) (
    lib.attrValues config.accounts.email.accounts
  );

  onOff = p: if p then "on" else "off";

  accountStr =
    account:
    with account;
    lib.concatStringsSep "\n" (
      [ "account ${name}" ]
      ++ lib.mapAttrsToList (n: v: n + " " + v) (
        {
          host = smtp.host;
          from = address;
          auth = "on";
          user = userName;
          tls = onOff smtp.tls.enable;
          tls_starttls = onOff smtp.tls.useStartTls;
        }
        // optionalAttrs (msmtp.tls.fingerprint != null) {
          tls_fingerprint = msmtp.tls.fingerprint;
        }
        // optionalAttrs (smtp.port != null) { port = toString smtp.port; }
        // optionalAttrs (smtp.tls.certificatesFile != null) {
          tls_trust_file = smtp.tls.certificatesFile;
        }
        // optionalAttrs (passwordCommand != null) {
          passwordeval = toString passwordCommand;
        }
        // msmtp.extraConfig
      )
      ++ lib.optional primary "account default : ${name}"
      ++ map (alias: ''

        account ${alias} : ${name}
        from ${alias}
      '') aliases
    );
in
{

  options = {
    programs.msmtp = {
      enable = lib.mkEnableOption "msmtp";

      package = lib.mkPackageOption pkgs "msmtp" { };

      configContent = mkOption {
        default = "";
        type = types.lines;
        example = lib.literalExpression ''
          lib.mkOrder 1200 ''''
            set syslog
          '''';
        '';
        description = ''
          Content added to msmtp config.
          See <https://marlam.de/msmtp/msmtprc.txt> for examples.

          Note, if running msmtp fails with the error message "account default
          was already defined" then you probably have an account command here.
          Account commands should be placed in
          [](#opt-accounts.email.accounts._name_.msmtp.extraConfig).
        '';
      };

      extraConfig = mkOption {
        type = types.lines;
        default = "";
        visible = false;
        apply =
          x:
          lib.warnIfNot (x == "") ''
            `programs.msmtp.extraConfig` is deprecated, use `programs.msmtp.configContent` instead.

            Example: programs.msmtp.configContent = lib.mkBefore "set syslog";
          '' x;
        description = ''
          Extra configuration lines to add to {file}`~/.msmtprc`.
          See <https://marlam.de/msmtp/msmtprc.txt> for examples.

          Note, if running msmtp fails with the error message "account default
          was already defined" then you probably have an account command here.
          Account commands should be placed in
          [](#opt-accounts.email.accounts._name_.msmtp.extraConfig).
        '';
      };

      extraAccounts = mkOption {
        type = types.lines;
        default = "";
        visible = false;
        apply =
          x:
          lib.warnIfNot (x == "") ''
            `programs.msmtp.extraAccounts` is deprecated, use `programs.msmtp.configContent` instead.

            Example: programs.msmtp.configContent = lib.mkAfter "set syslog";
          '' x;
        description = ''
          Extra configuration lines to add to the end of {file}`~/.msmtprc`.
          See <https://marlam.de/msmtp/msmtprc.txt> for examples.
        '';
      };
    };

    accounts.email.accounts = mkOption {
      type = with types; attrsOf (submodule (import ./accounts.nix));
    };
  };

  config = lib.mkIf cfg.enable (
    lib.mkMerge [
      {
        home.packages = [ cfg.package ];

        xdg.configFile."msmtp/config".text = cfg.configContent;

        programs.msmtp.configContent = lib.mkMerge [
          (lib.mkBefore "# Generated by Home Manager.")
          (lib.mkIf (cfg.extraConfig != "") (lib.mkBefore cfg.extraConfig))
          (lib.concatStringsSep "\n\n" (map accountStr msmtpAccounts))
          (lib.mkIf (cfg.extraAccounts != "") (lib.mkAfter cfg.extraAccounts))
        ];

        home.sessionVariables = {
          MSMTPQ_Q = "${config.xdg.dataHome}/msmtp/queue";
          MSMTPQ_LOG = "${config.xdg.dataHome}/msmtp/queue.log";
        };
      }
    ]
  );
}
