thunderbird: support ews accounts

Generate the Thunderbird identity and outgoing server preferences
needed for explicit accounts.email.accounts.<name>.ews accounts,
and add an outlook.office365.com-ews flavor preset for Office365
Exchange accounts.

Closes #8011
This commit is contained in:
Austin Horstman
2026-04-28 12:23:47 -05:00
parent c2f07e2dca
commit c357182707
4 changed files with 100 additions and 1 deletions

View File

@@ -412,6 +412,7 @@ let
"gmail.com"
"mailbox.org"
"migadu.com"
"outlook.office365.com-ews"
"outlook.office365.com"
"plain"
"posteo.de"
@@ -623,6 +624,17 @@ let
};
})
(mkIf (config.flavor == "outlook.office365.com-ews") {
userName = mkDefault config.address;
ews = {
host = "outlook.office365.com";
serviceDescriptionURL = "https://outlook.office365.com/EWS/Exchange.asmx";
authentication = "xoauth2";
tls.enable = true;
};
})
(mkIf (config.flavor == "fastmail.com") {
userName = mkDefault config.address;

View File

@@ -162,6 +162,9 @@ let
// optionalAttrs (identity.smtp != null) {
"mail.identity.id_${id}.smtpServer" = "smtp_${identity.id}";
}
// optionalAttrs (identity.smtp == null && account.ews != null) {
"mail.identity.id_${id}.smtpServer" = "ews_${account.id}";
}
// account.thunderbird.perIdentitySettings id;
toThunderbirdSMTP =
@@ -235,6 +238,7 @@ let
// optionalAttrs (account.ews != null) {
"mail.smtpserver.ews_${id}.type" = "ews";
"mail.outgoingserver.ews_${id}.auth_method" = toThunderbirdAuthMethod account.ews.authentication;
"mail.outgoingserver.ews_${id}.description" = account.name;
"mail.outgoingserver.ews_${id}.ews_url" = account.ews.serviceDescriptionURL;
"mail.outgoingserver.ews_${id}.key" = "ews_${id}";
"mail.outgoingserver.ews_${id}.username" = account.userName;
@@ -263,6 +267,9 @@ let
// optionalAttrs (account.smtp != null && account.primary) {
"mail.smtp.defaultserver" = "smtp_${id}";
}
// optionalAttrs (account.smtp == null && account.ews != null && account.primary) {
"mail.smtp.defaultserver" = "ews_${id}";
}
// builtins.foldl' (a: b: a // b) { } (
map (address: toThunderbirdIdentity account address) addresses
)
@@ -1163,7 +1170,10 @@ in
in
(builtins.listToAttrs (
map (a: {
name = "${thunderbirdProfilesPath}/${name}/ImapMail/${a.id}/msgFilterRules.dat";
name =
"${thunderbirdProfilesPath}/${name}/"
+ (if a.ews != null then "Mail" else "ImapMail")
+ "/${a.id}/msgFilterRules.dat";
value = {
text = mkFilterListToIni a.thunderbird.messageFilters;
};

View File

@@ -3,6 +3,7 @@
thunderbird-auth-methods = ./thunderbird-auth-methods.nix;
thunderbird-auth-warning = ./thunderbird-auth-warning.nix;
thunderbird-office365 = ./thunderbird-office365.nix;
thunderbird-exchange = ./thunderbird-exchange.nix;
thunderbird-with-firefox = ./thunderbird-with-firefox.nix;
thunderbird-native-messaging-host = ./thunderbird-native-messaging-host.nix;
}

View File

@@ -0,0 +1,76 @@
{
config,
pkgs,
...
}:
let
accountId = builtins.hashString "sha256" "work@example.com";
customAccountId = builtins.hashString "sha256" "custom@example.com";
inherit (pkgs.stdenv.hostPlatform) isDarwin;
profilesDir = if isDarwin then "Library/Thunderbird/Profiles" else ".thunderbird";
userJs = "home-files/${profilesDir}/default/user.js";
in
{
accounts.email.accounts."work@example.com" = {
address = "work@example.com";
flavor = "outlook.office365.com-ews";
primary = true;
realName = "Home Manager";
thunderbird.enable = true;
};
accounts.email.accounts."custom@example.com" = {
address = "custom@example.com";
ews = {
host = "ews.example.com";
serviceDescriptionURL = "https://ews.example.com/EWS/Exchange.asmx";
authentication = "ntlm";
};
realName = "Custom Exchange";
thunderbird = {
enable = true;
messageFilters = [
{
name = "Custom";
type = "17";
action = "Mark read";
condition = "ALL";
}
];
};
};
programs.thunderbird = {
enable = true;
package = config.lib.test.mkStubPackage {
name = "thunderbird";
};
profiles.default.isDefault = true;
};
nmt.script = ''
assertFileContains ${userJs} 'user_pref("mail.account.account_${accountId}.server", "server_${accountId}");'
assertFileContains ${userJs} 'user_pref("mail.smtp.defaultserver", "ews_${accountId}");'
assertFileContains ${userJs} 'user_pref("mail.identity.id_${accountId}.smtpServer", "ews_${accountId}");'
assertFileContains ${userJs} 'user_pref("mail.outgoingserver.ews_${accountId}.auth_method", 10);'
assertFileContains ${userJs} 'user_pref("mail.outgoingserver.ews_${accountId}.ews_url", "https://outlook.office365.com/EWS/Exchange.asmx");'
assertFileContains ${userJs} 'user_pref("mail.server.server_${accountId}.authMethod", 10);'
assertFileContains ${userJs} 'user_pref("mail.server.server_${accountId}.type", "ews");'
assertFileContains ${userJs} 'user_pref("mail.outgoingserver.ews_${customAccountId}.auth_method", 6);'
assertFileContains ${userJs} 'user_pref("mail.outgoingserver.ews_${customAccountId}.ews_url", "https://ews.example.com/EWS/Exchange.asmx");'
assertFileContains ${userJs} 'user_pref("mail.server.server_${customAccountId}.hostname", "ews.example.com");'
assertFileExists home-files/${profilesDir}/default/Mail/${customAccountId}/msgFilterRules.dat
assertFileContent \
home-files/${profilesDir}/default/Mail/${customAccountId}/msgFilterRules.dat \
${pkgs.writeText "thunderbird-ews-expected-msgFilterRules.dat" ''
version="9"
logging="no"
name="Custom"
enabled="yes"
type="17"
action="Mark read"
condition="ALL"
''}
'';
}