Autoconfiguration de thunderbird

Objectif Installer un service de configuration automatique pour thunderbird.

Références :

Étant donné une adresse email, thunderbird peut en déduire un URL d'autoconfiguration1), et utiliser cet URL pour découvrir tous les paramètres d'accès au compte de courriel, noms, ports et protocoles des serveurs de réception et d'émission ainsi que le type d'authentification et l'identifiant de connexion.

Ainsi, pour l'adresse marc.hassin@example.com, Thunderbird essayera tour à tour ces deux URL

  1. http://example.com/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress=marc.hassin@example.com
  2. http://autoconfig.example.com/mail/config-v1.1.xml?emailaddress=marc.hassin@example.com

La réponse doit être un fichier xml décrivant les divers serveurs, protocoles, ports etc… La réponse peut contenir des chaînes que thunderbird remplacera par leur valeurs effectives, comme par exemple, %EMAILADDRESS%, %EMAILLOCALPART%, %EMAILDOMAIN% et d'autres encore. Malheureusement, ces remplacements simples ne permettent pas dans notre cas d'établir la correspondance entre l'adresse de courriel et l'identifiant. Ie Marc.Hassin@example.commhassin@example.com ou simplement mhassin.

Il faudra donc qu'un script réponde à cet URL.

Ci-dessous, diverses impmémentations.

considérations de sécurité

Toutes ces méthodes présentent les inconvénients suivants :

  • Ces outils exposent l'identifiant d'un compte mail.
  • Ces outils permettent de déterminer les adresses valides (réponse xml) et les adresses non valides (aucune réponse, message d'erreur etc…).

Il appartient à chacun de décider si ces outils doivent être publics ou seulement disponibles dans un environnement contrôlé. L'aspect pratique peut disparaître pour un utilisateur si ces outils ne sont disponibles qu'à l'intérieur d'un établissement.

Le script CMtbcg.php

Une implémentation d'exemple en PHP. Elle utilise Net::LDAP2 pour la connexion au serveur LDAP. Assurez vous d'installer les paquets nécessaires sur votre serveur web. Pour les systèmes debuntu :

apt install php-net-ldap2

Ce script.

  1. vérifie le paramètre ?emailaddress :
    • ASCII seulement,:!: fonctionne avec des domaines internationaux ???
    • un seul @,
    • longueur totale < 321 octets,
    • longueur partie locale < 65 octets
  2. vérifie ensuite que le domaine de l'adresse de courriel est connu
  3. effectue une requête LDAP pour trouver l'UID correspondant à l'adresse mail
  4. meurt silencieusement sans aucun affichage au moindre problème
  5. renvoie le fichier xml sinon.

Script sous licence CeCILL V2.1, aucune garantie

Comme l'indique sa licence CECILL, il vous appartient de vérifier que ce script est convenable pour votre utilisation.

Cliquez sur le titre pour télécharger.

CMtbcg.php
<?php
// encoding: utf-8
/*
 * CMtbcg: Generate thunderbird XML configuration file. 
 *  
 *                   Copyright © Schplurtz Le Déboulonné, 2012, 2019
 *  
 *           Schplurtz le Déboulonné <Schplurtz Arobe laposte • net>
 *  
 *  licence: CECILL http://www.cecill.info/licences/Licence_CeCILL_V2.1-fr.html
 *  license: CECILL http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.html
 *                FRENCH                |            ENGLISH
 *  ------------------------------------+--------------------------------------
 *  Ce logiciel est un programme        | This software is a computer program
 *  informatique servant à générer un   | whose purpose is to generate an
 *  fichier d'autoconfiguration pour    | XML autoconfiguration file for
 *  thunderbird en interrogeant un      | thunderbird by querying an LDAP
 *  annuaire LDAP.                      | directory.
 *                                      |
 *  Ce logiciel est régi par la licence | This software is governed by the
 *  CeCILL soumise au droit français et | CeCILL license under French law and
 *  respectant les principes de         | abiding by the rules of
 *  diffusion des logiciels libres.     | distribution of free software.  You
 *  Vous pouvez utiliser, modifier      | can  use, modify and/ or
 *  et/ou redistribuer ce programme     | redistribute the software under the
 *  sous les conditions de la licence   | terms of the CeCILL license as
 *  CeCILL telle que diffusée par le    | circulated by CEA, CNRS and INRIA
 *  CEA, le CNRS et l'INRIA sur le site | at the following URL
 *  "http://www.cecill.info/".          | "http://www.cecill.info/".
 *                                      |
 *  En contrepartie de l'accessibilité  | As a counterpart to the access to
 *  au code source et des droits de     | the source code and  rights to
 *  copie, de modification et de        | copy, modify and redistribute
 *  redistribution accordés par cette   | granted by the license, users are
 *  licence, il n'est offert aux        | provided only with a limited
 *  utilisateurs qu'une garantie        | warranty  and the software's
 *  limitée.  Pour les mêmes raisons,   | author,  the holder of the economic
 *  seule une responsabilité restreinte | rights,  and the successive
 *  pèse sur l'auteur du programme,  le | licensors  have only  limited
 *  titulaire des droits patrimoniaux   | liability.
 *  et les concédants successifs.       |
 *                                      |
 *  A cet égard  l'attention de         | In this respect, the user's
 *  l'utilisateur est attirée sur les   | attention is drawn to the risks
 *  risques associés au chargement,  à  | associated with loading,  using,
 *  l'utilisation,  à la modification   | modifying and/or developing or
 *  et/ou au développement et à la      | reproducing the software by the
 *  reproduction du logiciel par        | user in light of its specific
 *  l'utilisateur étant donné sa        | status of free software, that may
 *  spécificité de logiciel libre, qui  | mean  that it is complicated to
 *  peut le rendre complexe à manipuler | manipulate,  and  that  also
 *  et qui le réserve donc à des        | therefore means  that it is
 *  développeurs et des professionnels  | reserved for developers  and
 *  avertis possédant  des              | experienced professionals having
 *  connaissances  informatiques        | in-depth computer knowledge. Users
 *  approfondies.  Les utilisateurs     | are therefore encouraged to load
 *  sont donc invités à charger  et     | and test the software's suitability
 *  tester  l'adéquation  du logiciel à | as regards their requirements in
 *  leurs besoins dans des conditions   | conditions enabling the security of
 *  permettant d'assurer la sécurité de | their systems and/or data to be
 *  leurs systèmes et ou de leurs       | ensured and,  more generally, to
 *  données et, plus généralement, à    | use and operate it in the same
 *  l'utiliser et l'exploiter dans les  | conditions as regards security.
 *  mêmes conditions de sécurité.       |
 *                                      |
 *  Le fait que vous puissiez accéder à |  The fact that you are presently
 *  cet en-tête signifie que vous avez  |  reading this means that you have
 *  pris connaissance de la licence     |  had knowledge of the CeCILL license
 *  CeCILL, et que vous en avez accepté |  and that you accept its terms.
 *  les termes.                         |
 */
 
$debug=false;
function meurs($s) {
    global $debug;
    if($debug) die($s); else die();
}
/*
 * Define an array with our domains, and their respective imap and smtp servers
 * Must be all lower case.
 */
 
$server=array(
    'example.com' => array( 'imap'         => 'imap.example.com',
                             'smtp'         => 'submission.example.com',
                             'displayname'  => 'La compagnie de France',
                             'displayshort' => 'compagnie',
                             // userhelpdoc is optional
                             'userhelpdoc'  => 'https://example.com/docs/email/thunderbird',
                         ),
    // 'more.domains' => array( 'imap' etc...),
);
 
/*
 * Check params, die if params are not what we expect
 */
if( ! isset( $_GET['emailaddress'] ))
    meurs('No email address provided');
 
/*
 * just make sure that we received less than 321 bytes, see RFC.
 */
if( 320 < strlen( $_GET['emailaddress'] ))
    meurs('Email address too long');
 
$candidate=trim($_GET['emailaddress']);
list($local,$domain)=explode('@', $candidate, 2);
$domain=strtolower($domain);
$domaindc=str_replace('.', ',dc=', $domain);
/*
 * Check domain is known.
 */
if( ! array_key_exists( $domain, $server ) )
    meurs('Unknown domain : '.$domain);
 
/*
 * check local part corresponds to OUR likings. Well... this is a minimalist
 * test. Just make sure we only have only ASCII chars we use for email at our
 * site and that the length is less than 65, as per RFC 3696.
 */
if( ! preg_match( '/^[a-z][-_.a-z0-9]{0,63}$/i', $local ) )
  meurs('Weird chars in email or local part too long');
 
/*
 * Now that we are certain that emailaddress
 *   - is shorter than 321 bytes
 *   - has a known domain part
 *   - has only valid chars in its local part
 *   - has a localpart shorter than 65 chars
 * let's work !
 */
$email=$_GET['emailaddress'];
 
$fmtnodoc=<<<'EOFMT'
<?xml version="1.0" encoding="UTF-8"?>
 
<clientConfig version="1.1">
  <emailProvider id="%s">
    <domain>%s</domain>
    <displayName>%s</displayName>
    <displayShortName>%s</displayShortName>
    <incomingServer type="imap">
      <hostname>%s</hostname>
      <port>993</port>
      <socketType>SSL</socketType>
      <authentication>password-cleartext</authentication>
      <username>%s</username>
    </incomingServer>
    <outgoingServer type="smtp">
      <hostname>%s</hostname>
      <port>587</port>
      <socketType>STARTTLS</socketType>
      <authentication>password-cleartext</authentication>
      <username>%s</username>
    </outgoingServer>
  </emailProvider>
</clientConfig>
EOFMT;
$fmtdoc=<<<'EOFMT'
<?xml version="1.0" encoding="UTF-8"?>
 
<clientConfig version="1.1">
  <emailProvider id="%s">
    <domain>%s</domain>
    <displayName>%s</displayName>
    <displayShortName>%s</displayShortName>
    <incomingServer type="imap">
      <hostname>%s</hostname>
      <port>993</port>
      <socketType>SSL</socketType>
      <authentication>password-cleartext</authentication>
      <username>%s</username>
    </incomingServer>
    <outgoingServer type="smtp">
      <hostname>%s</hostname>
      <port>587</port>
      <socketType>STARTTLS</socketType>
      <authentication>password-cleartext</authentication>
      <username>%s</username>
    </outgoingServer>
    <documentation url="%s">
      <descr lang="en">Thunderbird mail settings</descr>
      <descr lang="fr">Pramètres de courriel pour Thunderbird</descr>
    </documentation>
  </emailProvider>
</clientConfig>
EOFMT;
 
require_once 'Net/LDAP2.php';
 
$LDAPconfig = array (
    'host'      => 'annuaire.example.com',
    'port'      => 389,
    'version'   => 3,
    'starttls'  => false,
    // 'binddn'    => 'cn=admin,ou=people,dc=example.dc=com',
    // 'bindpw'    => 'password',
    'basedn'    => 'ou=people,dc='.$domaindc, // default basedn for queries
    'options'   => array(),
    'filter'    => '(objectclass=*)', //default search filter
    'scope'     => 'one',             // default scope for search
);
 
// Connecting using the configuration:
$ldap = Net_LDAP2::connect($LDAPconfig);
 
// Testing for connection error
if (PEAR::isError($ldap)) {
    meurs('Could not connect to LDAP-server: '.$ldap->getMessage());
}
 
$queryparam=array(
    'scope'      => 'one',
    'sizelimit'  => 0,               // Number of entries returned at maximum
    'timelimit'  => 10,              // Seconds to spent for searching
    'attrsonly'  => false,           // If true, only attribute names are returned
    'attributes' => array ( 'uid' ), // Array of attribute names, which the entry should contain.
);
 
$search = $ldap->search( null, "(mail=$email)", $queryparam );
 
// Test for search errors:
if (PEAR::isError($search)) {
    meurs($search->getMessage() . "\n");
}
 
// if not exactly one entry, we can't tell user...
if( $search->count() !== 1 ) {
    meurs('no answer or  more than one answer. count : '.$search->count() );
}
 
$entry=$search->shiftEntry();
$uid = $entry->getValue('uid', 'single');
if(false === $uid) {
    meurs('Weird ! Answer has no "uid" attribute');
}
 
header( 'Content-type: text/xml' );
if(array_key_exists('userhelpdoc', $server[$domain]) and ! empty($server[$domain]['userhelpdoc'])) {
    printf($fmtdoc,
           $domain,
           $domain,
           $server[$domain]['displayname'],
           $server[$domain]['displayshort'],
           $server[$domain]['imap'],
           $uid,
           $server[$domain]['smtp'],
           $uid,
           $server[$domain]['userhelpdoc']
          );
}
else {
    printf($fmtnodoc,
           $domain,
           $domain,
           $server[$domain]['displayname'],
           $server[$domain]['displayshort'],
           $server[$domain]['imap'],
           $uid,
           $server[$domain]['smtp'],
           $uid
          );
} 
// vim: se ts=4 sw=4 et ai mouse= :

Exemple de configuration apache

autoconfig.compagie.fr.conf
<VirtualHost *:80>
	# ServerAdmin Super.User@example.com
	# ServerName autoconfig.example.com
	ServerSignature Off
 
	<Directory />
		Options FollowSymLinks
		AllowOverride None
		Require all denied
	</Directory>
	<Directory /var/www-autoconfig>
		Require all granted
	</Directory>
 
	ErrorLog /var/log/apache2/error.autoconfig.log
 
	# Possible values include: debug, info, notice, warn, error, crit,
	# alert, emerg.
	LogLevel warn
 
	CustomLog /var/log/apache2/access.autoconfig.log combined
 
	Alias /mail/config-v1.1.xml /var/www-autoconfig/CMtbcg.php
</VirtualHost>

AutoMX

AutoMX2 est un outil qui va faire ce genre de choses pour Thunderbird, mais aussi pour les produits Microsoft et Apple. En une seule fois ! L'outil est un peu capricieux, et pas super documenté à mon goût, mais par contre, on trouve sur les archives de la liste smtp.fr, un exemple de configuration.

From: Laurent Spagnol < laurent • spagnol à univ-reims • fr >
To: smtp-fr à groupes • renater • fr
Subject: Re: Autoconfig pour client de messagerie
Date: Thu, 9 Apr 2020 17:00:52 +0200

“Facile” avec “AutoMX” → https://automx.org/

Configuration DNS

Il faut trois noms DNS, un pour répondre à thunderbird, un autre pour réponde à outlook, et un dernier pour les mobiles (d'apple ?).

autoconfig      IN CNAME SERVEURAPACHEAUTOCONF.fr.
autodiscover    IN CNAME SERVEURAPACHEAUTOCONF.fr.
mail-autoconf   IN CNAME SERVEURAPACHEAUTOCONF.fr. 

automx.conf config du logiciel

Voilà la configuration du logiciel automx.

/etc/automx.conf
[automx]
provider = mondomaine.fr
domains = mondomaine.fr, subdomaine.mondomaine.fr
#debug = yes
logfile = /tmp/automx.log
 
# Protect against DoS
memcache = 127.0.0.1:11211
memcache_ttl = 600
client_error_limit = 5
rate_limit_exception_networks = 127.0.0.0/8, ::1/128
 
# The DEFAULT section is always merged into each other section. Each section
# can overwrite settings done here.
[DEFAULT]
account_type = email
account_name = mondomaine
account_name_short = mondomaine
 
[global]
action = settings
 
backend = ldap
host = ldap://ldap.mondomaine.fr
base = ou=people,dc=mondomaine,dc=fr
binddn = cn=comptemagique,ou=system,dc=mondomaine,dc=fr
bindpw = PASSWORD
result_attrs = mail, mailAlternateAddress, uid
scope = one
filter = (|(mailAlternateAddress=%s)(mail=%s))
 
pop = no
 
imap = yes
imap_server = imaps.mondomaine.fr
imap_port = 993
imap_encryption = ssl
imap_auth = plaintext
imap_refresh_ttl = 6
imap_auth_identity = ${uid}
 
smtp = yes
smtp_server = smtps.mondomaine.fr
smtp_port = 465
smtp_encryption = ssl
smtp_auth = plaintext
smtp_refresh_ttl = 6
smtp_auth_identity = ${uid}
smtp_default = yes
smtp_author = ${mail}

Configuration apache

Et une partie de la config Apache

/etc/apache2/sites-available/automx.conf
ServerAdmin email-admin@MONDOMAINE.fr
CustomLog /var/log/apache2/access.log combined
ErrorLog /var/log/apache2/error.log
 
# Securite de base
ServerSignature Off
ServerTokens Prod
<Files ~ "test\.php|~$|\.conf|\.cf|\.bak">
Require all denied
</Files>
<Directory />
Require all denied
AllowOverride None
Options -Indexes
</Directory>
 
# Bloquer les acces directs sur adresse IP
<VirtualHost *:80>
ServerName a.b.c.d
ServerAlias a:b:cd::e
Redirect 403 /
ErrorDocument 403 "<h1>Forbidden</h1><p>Direct IP access not
allowed.</p>"
</VirtualHost>
 
# Redirection => https (Mobiles => formulaire autoconf)
<VirtualHost *:80>
ServerName mail-autoconf.MONDOMAINE.fr
Redirect "/" "https://mail-autoconf.MONDOMAINE.fr/";
</VirtualHost>
 
# Redirection => https (Thunderbird personnels)
<VirtualHost *:80>
ServerName autoconfig.MONDOMAINE.fr
Redirect "/" "https://autoconfig.MONDOMAINE.fr/";
</VirtualHost>
 
# Redirection => https (Thunderbird subdomaine)
<VirtualHost *:80>
ServerName autoconfig.subdomaine.MONDOMAINE.fr
Redirect "/" "https://autoconfig.subdomaine.MONDOMAINE.fr/";
</VirtualHost>
 
# Thunderbird se connecter en HTTP, mais peut suivre une redirection HTTPS
# Les clients Microsoft se connectent toujours en HTTPS
 
#SSLStaplingCache shmcb:${APACHE_RUN_DIR}/ssl_stapling(128000)
<VirtualHost *:443>
 
ServerName  mail-autoconf.MONDOMAINE.fr
ServerAlias  autodiscover.MONDOMAINE.fr
ServerAlias    autoconfig.MONDOMAINE.fr
ServerAlias  autodiscover.subdomaine.MONDOMAINE.fr
ServerAlias    autoconfig.subdomaine.MONDOMAINE.fr
 
<IfModule mod_wsgi.c>
WSGIScriptAliasMatch (?i)^/.+/config-v1.1.xml /usr/local/lib/automx/automx_wsgi.py
WSGIScriptAliasMatch (?i)^/.+/autodiscover.xml /usr/local/lib/automx/automx_wsgi.py
WSGIScriptAliasMatch (?i)^/.+/Autodiscover.xml /usr/local/lib/automx/automx_wsgi.py
WSGIScriptAliasMatch (?i)^/mobileconfig /usr/local/lib/automx/automx_wsgi.py
<Directory "/usr/local/lib/automx">
Require all granted
</Directory>
</IfModule>
 
DocumentRoot /var/www/automx
 
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
 
SSLEngine On
SSLCertificateKeyFile /etc/apache2/ssl/mail-autoconf.MONDOMAINE.fr.key
SSLCertificateFile /etc/apache2/ssl/mail-autoconf.MONDOMAINE.fr.crt
SSLCertificateChainFile /etc/apache2/ssl/DigiCertCA.crt
SSLProtocol ALL -SSLv2 -SSLv3
SSLHonorCipherOrder On
SSLCipherSuite ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS
SSLCompression Off
#SSLUseStapling On
#SSLStaplingResponderTimeout 5
#SSLStaplingReturnResponderErrors off
 
</VirtualHost>
 
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

autoconfig.pl

Une autre implémentation en perl, à installer en cgibin, proposée par < sebastien • pose à ac-reunion • fr >. Il faut adapter le nom du serveur dans le code, la base de recherche et bien sûr le filtre, sans oublier les valeurs du document XML. Et puis c'est tout. Simple, direct,

autoconfig.pl
#!/usr/bin/perl -W
 
use strict;
use Net::LDAP;
 
#print "Content-type: text/html\n\n";
 
my ($mail,$uid);
 
if (defined $ENV{QUERY_STRING}) {
	my @query = split(/=/, $ENV{QUERY_STRING});
	if (defined $query[1]) {
		$query[1] =~ s/%40/@/;
		$mail = $query[1];
 
		my $ldap = Net::LDAP->new( 'ldapserveur.mondomaine.fr' ) or die "$@";
		my $mesg = $ldap->bind ;
 
		$mesg = $ldap->search( base   => "ou=personnels dc=mondomaine, dc=fr",
				filter => "(|(mail=$mail)(mailalternateaddress=$mail)(mailequivalentaddress=$mail))",
				attrs  => ['uid']
				);
 
		if ($mesg->code) {
			$uid = $mesg->error;
		} 
		else {
			if (defined $mesg->entry) {
				$uid = $mesg->entry->get_value('uid');
			} 
			else {
				$uid='Verifiez votre adresse email';
			}
		}
		$mesg = $ldap->unbind;
	}
	else { $uid = 'Verifiez votre adresse email'; }
}
 
 
 
 
 
print "Content-type: application/xml\n\n";
 
print '<?xml version="1.0"?>';
print '<clientConfig version="1.1">';
 
print '    <emailProvider id="mondomaine.fr">';
print '      <domain>mondomaine.fr</domain>';
print '      <displayName>Messagerie de Mon Domaine</displayName>';
print '      <displayShortName>Mondomaine</displayShortName>';
 
print '      <incomingServer type="imap">';
print '         <hostname>imaps.mondomaine.fr</hostname>';
print '         <port>993</port>';
print '         <socketType>SSL</socketType>';
print "         <username>$uid</username>";
print '         <authentication>password-cleartext</authentication>';
print '      </incomingServer>';
 
print '      <outgoingServer type="smtp">';
print '         <hostname>smtps.mondomaine.fr</hostname>';
print '         <port>465</port>';
print '         <socketType>SSL</socketType>';
print "         <username>$uid</username>";
print '         <authentication>password-cleartext</authentication>';
print '         <addThisServer>true</addThisServer>';
print '         <useGlobalPreferredServer>true</useGlobalPreferredServer>';
print '      </outgoingServer>';
 
print '    </emailProvider>';
print '</clientConfig>';

1)
He ben non ! Thunderbird n'utilise pas les enregistrements DNS SRV «We may add DNS SRV records as supported mechanism in the future, but we currently do not.» De toute façon, il n'y aurait pas toutes les informations requises