{
  config,
  lib,
  pkgs,
  ...
}:
let
  accounts = lib.filter (a: a.enable && a.getmail.enable) (
    lib.attrValues config.accounts.email.accounts
  );

  renderAccountConfig =
    account:
    let
      inherit (account) getmail imap passwordCommand;
      passCmd = lib.concatMapStringsSep ", " (x: "'${x}'") passwordCommand;
      renderedMailboxes = lib.concatMapStrings (x: "'${x}', ") getmail.mailboxes;
      retrieverType = if imap.tls.enable then "SimpleIMAPSSLRetriever" else "SimpleIMAPRetriever";
      destination =
        if getmail.destinationCommand != null then
          {
            destinationType = "MDA_external";
            destinationPath = getmail.destinationCommand;
          }
        else
          {
            destinationType = "Maildir";
            destinationPath = "${account.maildir.absPath}/";
          };
      renderGetmailBoolean = v: if v then "true" else "false";
    in
    ''
      # Generated by Home-Manager.
      [retriever]
      type = ${retrieverType}
      server = ${imap.host}
      ${lib.optionalString (imap.port != null) "port = ${toString imap.port}"}
      username = ${account.userName}
      password_command = (${passCmd})
      mailboxes = ( ${renderedMailboxes} )

      [destination]
      type = ${destination.destinationType}
      path = ${destination.destinationPath}

      [options]
      delete = ${renderGetmailBoolean getmail.delete}
      read_all = ${renderGetmailBoolean getmail.readAll}
    '';
  getmailEnabled = lib.length accounts > 0;
  # Watch out! This is used by the getmail.service too!
  renderConfigFilepath = a: ".getmail/getmail${if a.primary then "rc" else a.name}";

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

  config = lib.mkIf getmailEnabled {
    assertions = [
      (lib.hm.assertions.assertPlatform "programs.getmail" pkgs lib.platforms.linux)
    ];

    home.file = lib.mergeAttrsList (
      map (a: { "${renderConfigFilepath a}".text = renderAccountConfig a; }) accounts
    );
  };
}
