Expérience de migration de mailman2 à mailman3

#1

Bonjour,

Je rend compte ici de mon expérience de migration de mailman2 à mailman3. En partant d’une nouvelle installation de mailman2 (en trichant avec un container docker) avec quelques données pour faire semblant.

En supposant un reverse proxy SSL vers le port :8080 sur chat.the.re, on peut faire:

  • mkdir -p archives/private
  • sudo chown -R list:list archives
  • docker run --rm -e URL_PATTERN=https -v $(pwd)/lists:/var/lib/mailman/lists -v $(pwd)/archives:/var/lib/mailman/archives -p 8080:80 --name mailman --add-host chat.the.re:127.0.0.1 --hostname chat.the.re -e URL_HOST=chat.the.re -e EMAIL_HOST=chat.the.re -e LIST_ADMIN=loic@dachary.org
    -e MASTER_PASSWORD=“example” d3fk/mailman2

Puis créer une liste list1 via l’interface web et y envoyer un courriel avec:

  • docker exec -ti mailman bash
  • ( echo ‘Subject: test’ ; echo ; echo ‘content’ ) | sendmail -v -F ‘Loic Dachary’ -f loic@dachary.org list1@chat.the.re

Et ensuite modérer le courriel puis aller voir sur https://chat.the.re/lists/private/list1 après quelques minutes pour vérifier qu’il est bien arrivé et archivé.

Pour installer mailman3 j’installe les paquets debian. J’ai été voir les instructions du wiki qui ne contiennent pas d’information utile.

  • Ne pas suivre les instructions de /usr/share/doc/mailman3/README.Debian pour postfix (ça casse postfix parce que /var/lib/mailman3/data/postfix_lmtp n’existe pas).
  • Suivre les instructions de /usr/share/doc/mailman3-web/README.Debian.gz
    • sudo mkdir /var/log/nginx/mailman3 ; sudo chown www-data /var/log/nginx/mailman3
    • django-admin createsuperuser --pythonpath /usr/share/mailman3-web --settings settings --username admin --email loic@dachary.org
  • Si l’installation ne se fait pas bien (pourquoi je ne sais pas mais c’est arrivé une fois) Il faut copier admin_pass de /etc/mailman3/mailman.cfg dans MAILMAN_REST_API_PASS (vide de base) /etc/mailman3/mailman-web.py pour que https://example.com/postorius/lists/ fonctionne sinon c’est erreur 500
  • Changer la valeur de EMAILNAME dans /etc/mailman3/mailman-web.py
  • sudo systemctl restart webmail3-web

A suivre

2 Likes
#2

Je tente l’import d’une liste qui vient de mailman 2.1, après l’avoir créée comme recommandée (via l’interface web).

# mailman import21 spip-dev@chat.the.re /tmp/config.pck 
Traceback (most recent call last):
  File "/usr/bin/mailman", line 11, in <module>
    load_entry_point('mailman==3.2.1', 'console_scripts', 'mailman')()
  File "/usr/lib/python3/dist-packages/click/core.py", line 764, in __call__
    return self.main(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/usr/lib/python3/dist-packages/mailman/bin/mailman.py", line 69, in invoke
    return super().invoke(ctx)
  File "/usr/lib/python3/dist-packages/click/core.py", line 1137, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/lib/python3/dist-packages/click/core.py", line 956, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/lib/python3/dist-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/click/decorators.py", line 17, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/usr/lib/python3/dist-packages/mailman/commands/cli_import.py", line 64, in import21
    pickle_file, encoding='utf-8', errors='ignore')
ModuleNotFoundError: No module named 'Mailman'

On dirait bien que ça correspond à un problème discuté en juillet 2019 sur la liste mailman et corrigé depuis. Mais apparament pas dans la version 3.2.1 qui est installée par défaut dans buster. Il n’y a pas un mouvement important sur la page du package et il a été retiré de testing en mai 2020, donc installer un package depuis testing ne va pas aider. La version 3.2.2 est packagée dans sid mais … le patch n’est disponible qu’à partir de la 3.3.0, c’est ballot. Du coup je vais installer mailman dans un venv pour avoir les versions les plus récentes du script d’import.

#3

Installation de mailman3 dans un virtualenv à partir des sources

# git clone https://gitlab.com/mailman/mailman
# python3 -m venv venv
# apt-get instlal python3-dev
# cd mailman
# source ../venv/bin/activate
# pip install -e .

Mais ça révèle une autre erreur:

# mailman import21 spip-dev@chat.the.re /tmp/config.pck
Usage: mailman import21 [OPTIONS] LISTSPEC PICKLE_FILE
Try 'mailman import21 -h' for help.

Error: Not a Mailman 2.1 configuration file: <_io.BufferedReader name='/tmp/config.pck'>

En extrayant le message d’erreur

# git diff
diff --git a/src/mailman/commands/cli_import.py b/src/mailman/commands/cli_import.py
index 2d694a325..f82c9272f 100644
--- a/src/mailman/commands/cli_import.py
+++ b/src/mailman/commands/cli_import.py
@@ -71,9 +71,9 @@ def import21(ctx, listspec, pickle_file):
                     pickle_file, encoding='utf-8', errors='ignore')
             except EOFError:
                 break
-            except pickle.UnpicklingError:
+            except pickle.UnpicklingError as e:
                 ctx.fail(
-                    _('Not a Mailman 2.1 configuration file: $pickle_file'))
+                    _(f'Not a Mailman 2.1 configuration file: $pickle_file {e}'))
             else:
                 if not isinstance(config_dict, dict):
                     print(_('Ignoring non-dictionary: {0!r}').format(

on obtient

#  mailman import21 spip-dev@chat.the.re /tmp/config.pck 
Usage: mailman import21 [OPTIONS] LISTSPEC PICKLE_FILE
Try 'mailman import21 -h' for help.

Error: Not a Mailman 2.1 configuration file: <_io.BufferedReader name='/tmp/config.pck'> pickle data was truncated

Et en effet… :man_facepalming: je n’avais pas copié le bon fichier. Du coup ça marche mieux avec le bon fichier.

# mailman import21 spip-dev@chat.the.re /tmp/config.pck                      
Importing members     [####################################]  100%                                                           
Importing defers      [####################################]  100%
Importing rejects     [####################################]  100%
Importing discards    [####################################]  100%
#4

Pour l’import des mbox il y a des instructions qui ne fonctionnent pas:

# python manage.py hyperkitty_import -l foo-list@example.com $var_prefix/archives/private/foo-list.mbox/foo-list.mbox
python: can't open file 'manage.py': [Errno 2] No such file or directory

et les instructions de archlinux non plus parce que les choses ne sont pas installées au même endroit sur debian.

# django-admin hyperkitty_import --pythonpath /usr/share/webapps/hyperkitty --settings settings -l ADDRESS mbox_file 
Traceback (most recent call last):
  File "/usr/bin/django-admin", line 21, in <module>
    management.execute_from_command_line()
  File "/usr/lib/python3/dist-packages/django/core/management/__init__.py", line 364, in execute_from_command_line
    utility.execute()
  File "/usr/lib/python3/dist-packages/django/core/management/__init__.py", line 308, in execute
    settings.INSTALLED_APPS
  File "/usr/lib/python3/dist-packages/django/conf/__init__.py", line 56, in __getattr__
    self._setup(name)
  File "/usr/lib/python3/dist-packages/django/conf/__init__.py", line 41, in _setup
    self._wrapped = Settings(settings_module)
  File "/usr/lib/python3/dist-packages/django/conf/__init__.py", line 110, in __init__
    mod = importlib.import_module(self.SETTINGS_MODULE)
  File "/usr/lib/python3.7/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 965, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'settings'

Une personne qui connait bien django va s’en sortir parce que le module est bien la:

# dpkg -L python3-django-hyperkitty | grep import
/usr/lib/python3/dist-packages/hyperkitty/management/commands/hyperkitty_import.py
/usr/lib/python3/dist-packages/hyperkitty/tests/commands/test_import.py

et qu’il faut juste savoir comment appeler django pour qu’il le trouve.

#5

Après avoir cherché en vain sur le net, je me suis décidé à regarder comment mailman3-web est lancé. Parce qu’il doit bien avoir ce qu’il faut pour importer les modules, vu qu’il marche. Et en regardant dans /etc/mailman3/uwsgi.ini je vois qu’il tourne dans le dossier /usr/share/mailman3-web et que si on se déplace dedans, soudain c’est possible de faire python manage.py hyperkitty_import

#  python3 manage.py hyperkitty_import --help
usage: manage.py hyperkitty_import [-h] [--version] [-v {0,1,2,3}]
                                   [--settings SETTINGS]
                                   [--pythonpath PYTHONPATH] [--traceback]
                                   [--no-color] [--delete] [-l LIST_ADDRESS]
                                   [--no-sync-mailman] [--since SINCE]
                                   [--ignore-mtime]
                                   mbox [mbox ...]

Imports the specified mailbox archive

positional arguments:
  mbox

optional arguments:
  -h, --help            show this help message and exit
  --version             show program's version number and exit
  -v {0,1,2,3}, --verbosity {0,1,2,3}
                        Verbosity level; 0=minimal output, 1=normal output,
                        2=verbose output, 3=very verbose output
  --settings SETTINGS   The Python path to a settings module, e.g.
                        "myproject.settings.main". If this isn't provided, the
                        DJANGO_SETTINGS_MODULE environment variable will be
                        used.
  --pythonpath PYTHONPATH
                        A directory to add to the Python path, e.g.
                        "/home/djangoprojects/myproject".
  --traceback           Raise on CommandError exceptions
  --no-color            Don't colorize the command output.
  --delete              Delete poll instead of closing it
  -l LIST_ADDRESS, --list-address LIST_ADDRESS
                        the full list address the mailbox will be imported to
  --no-sync-mailman     do not sync properties with Mailman (faster, useful
                        for batch imports)
  --since SINCE         only import emails later than this date. Defaults to
                        the date of the newest message in the existing archive
                        if any.
  --ignore-mtime        do not check mbox mtimes (slower)
#6
# cd /usr/share/mailman3-web
# time python3 manage.py hyperkitty_import --list-address spip-dev@chat.the.re --since 2000-01-01 --no-sync-mailman /home/debian/spip-dev.mbox/*.mbox
...
Importing from mbox file /home/debian/spip-dev.mbox/200002.mbox to spip-dev@chat.the.re
...
Traceback (most recent call last):
  File "manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/usr/lib/python3/dist-packages/django/core/management/__init__.py", line 364, in execute_from_command_line
    utility.execute()
  File "/usr/lib/python3/dist-packages/django/core/management/__init__.py", line 356, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/lib/python3/dist-packages/django/core/management/base.py", line 283, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/usr/lib/python3/dist-packages/django/core/management/base.py", line 330, in execute
    output = self.handle(*args, **options)
  File "/usr/lib/python3/dist-packages/hyperkitty/management/commands/hyperkitty_import.py", line 305, in handle
    importer.from_mbox(mbfile)
  File "/usr/lib/python3/dist-packages/hyperkitty/management/commands/hyperkitty_import.py", line 169, in from_mbox
    "subject", TEXTWRAP_RE.sub(" ", message["subject"]))
  File "/usr/lib/python3.7/email/message.py", line 555, in replace_header
    self._headers[i] = self.policy.header_store_parse(k, _value)
  File "/usr/lib/python3.7/email/policy.py", line 145, in header_store_parse
    raise ValueError("Header values may not contain linefeed "
ValueError: Header values may not contain linefeed or carriage return characters

Et c’est la que le vrai travail manuel commence. Mais on peut déjà voir que ça marche sur l’interface web et c’est réconfortant.

Ca vaut peut-être le coup de tenter l’import en utilisant une version plus récente de hyperkitty ?

1 Like