
Various patches for mm3 stable 3.3.1
by Ruth Ivimey-Cook
Folks,
For my own purposes I have created some patches which apply to the
current mailman pip package.
The first of them is for my purposes necessary, and has been discussed
here before: being able to specify the address used to listen for tcp
connections independently of the address the server considers it to be
accessible at. A possible change to this patch would be to check
whether this address was undefined but the old hostname was defined,
and use that if so. For me this is not needed, and in any case it is a
trivial change to make.
The second patch adds a bunch of additional logging calls to various
network-related parts of the package. I wrote these into the package
because I was seeking the cause of template expansion causing messages
to be silently dropped. I eventually found the cause was that I had an
incorrect setting of the template root URL, but I regard the lack of
anything in the logs as just as much of a bug. One important part of
those changes was that I added a try/catch around two parts of the
'decorate' code, which is where the silent dropping occurred. If you
only take one part of this patch, I encourage you to take this part.
For the third patch, I discovered that the task runner was at one point
busy-waiting to the tune of 100% cpu, and the cause was the way that
the runner checked to see if there was work left in the queue. I am not
quite sure what was the exact problem, but I think it was that there
was something to do, but it was not achievable at that time, and the
result was continual retry. The third patch changes the logic slightly
so that this no longer occurs - retry will happen, but somewhat more
gracefully.
I hope you find some use in these three.
Finally, I am currently experiencing problems with templates and would
appreciate any thoughts:
1. If I do not set up 'individual' or 'full' personalisation, all is
well and the default footer templates are expanded as expected. However
setting up personalisation causes template expansion to fail
completely, and messages get sent with a blank expansion.
2. I would find the postorius UI much easier to cope with if the
default template was 'populated' into the UI wherever it was non-blank,
rather than the UI starting off as if no templates were defined at all.
Regards,
Ruth
5 years

Re: Hacking attempts?
by Tim Cutts
You could use an application like fail2ban to watch your mailman/web logs and automatically firewall off attacking IP addresses which cause a lot of these errors in a defined window of time. This application is independent from mailman, and you can use it to protect against all kinds of brute force attacks. Ssh, web, mail - anything that creates a log file recording errors from remote IP addresses.
Just be careful when configuring it for remote servers so you don’t saw off the branch you’re sitting on…. I run a mail server for my family, and on one occasion a family member repeatedly got her password wrong which caused fail2ban to lock all of us out because it blocked our home NAT address, and I had to use my mobile phone to unblock us. :-)
Tim
> On 14 Jul 2022, at 08:29, Lists via Mailman-users <mailman-users(a)mailman3.org> wrote:
>
> Hi,
>
> We are seeing thousands of these emails every day, looks like someone is trying to hack our Mailman3 but would appreciate someone with more knowledge of MM3 to confirm.
>
> Is this a problem with our setup? i.e. the “Internal Server Error” bit, or are the hackers just sending bad data that is causing the error? also how do we stop/block this?
>
> TIA and here is a typical email:
>
>
> Subject: [Django] ERROR (EXTERNAL IP): Internal Server Error: /mailman3/accounts/fedora/login/
>
> Internal Server Error: /mailman3/accounts/fedora/login/
>
> TypeError at /accounts/fedora/login/
> _openid_consumer() missing 2 required positional arguments: 'provider' and 'endpoint'
>
> Request Method: GET
> Request URL: https://mailman.ardc.net/mailman3/accounts/fedora/login/?process=login&next… <https://mailman.ardc.net/mailman3/accounts/fedora/login/?process=login&next…>
> Django Version: 2.2.26
> Python Executable: /usr/bin/uwsgi-core
> Python Version: 3.9.2
> Python Path: ['.', '', '/usr/lib/python39.zip', '/usr/lib/python3.9', '/usr/lib/python3.9/lib-dynload', '/usr/local/lib/python3.9/dist-packages', '/usr/lib/python3/dist-packages', '/usr/lib/python3.9/dist-packages']
> Server time: Thu, 14 Jul 2022 02:34:04 -0400
> Installed Applications:
> ('hyperkitty',
> 'postorius',
> 'django_mailman3',
> 'django.contrib.admin',
> 'django.contrib.auth',
> 'django.contrib.contenttypes',
> 'django.contrib.sessions',
> 'django.contrib.sites',
> 'django.contrib.messages',
> 'django.contrib.staticfiles',
> 'rest_framework',
> 'django_gravatar',
> 'compressor',
> 'haystack',
> 'django_extensions',
> 'django_q',
> 'allauth',
> 'allauth.account',
> 'allauth.socialaccount',
> 'django_mailman3.lib.auth.fedora')
> Installed Middleware:
> ('django.contrib.sessions.middleware.SessionMiddleware',
> 'django.middleware.common.CommonMiddleware',
> 'django.middleware.csrf.CsrfViewMiddleware',
> 'django.middleware.locale.LocaleMiddleware',
> 'django.contrib.auth.middleware.AuthenticationMiddleware',
> 'django.contrib.messages.middleware.MessageMiddleware',
> 'django.middleware.clickjacking.XFrameOptionsMiddleware',
> 'django.middleware.security.SecurityMiddleware',
> 'django_mailman3.middleware.TimezoneMiddleware',
> 'postorius.middleware.PostoriusMiddleware')
>
>
> Traceback:
>
> File "/usr/lib/python3/dist-packages/django/core/handlers/exception.py" in inner
> 34. response = get_response(request)
>
> File "/usr/lib/python3/dist-packages/django/core/handlers/base.py" in _get_response
> 115. response = self.process_exception_by_middleware(e, request)
>
> File "/usr/lib/python3/dist-packages/django/core/handlers/base.py" in _get_response
> 113. response = wrapped_callback(request, *callback_args, **callback_kwargs)
>
> File "/usr/lib/python3/dist-packages/django/views/generic/base.py" in view
> 71. return self.dispatch(request, *args, **kwargs)
>
> File "/usr/lib/python3/dist-packages/django/views/generic/base.py" in dispatch
> 97. return handler(request, *args, **kwargs)
>
> File "/usr/lib/python3/dist-packages/django_mailman3/lib/auth/fedora/views.py" in get
> 56. return self.post(request, *args, **kwargs)
>
> File "/usr/lib/python3/dist-packages/django_mailman3/lib/auth/fedora/views.py" in post
> 67. client = _openid_consumer(request)
>
> Exception Type: TypeError at /accounts/fedora/login/
> Exception Value: _openid_consumer() missing 2 required positional arguments: 'provider' and 'endpoint'
> Request information:
> USER: AnonymousUser
>
> GET:
> process = 'login'
> next = '/mailman3/hyperkitty/list/44net(a)mailman.ampr.org <mailto:mailman3/hyperkitty/list/44net@mailman.ampr.org>/message/O5Z2YZBJZXFPH2ACAORN6BST7B2S3M3P/'
>
> POST: No POST data
>
> FILES: No FILES data
>
> COOKIES: No cookie data
>
> META:
> CONTEXT_DOCUMENT_ROOT = '/var/www/html'
> CONTEXT_PREFIX = ''
> DOCUMENT_ROOT = '/var/www/html'
> GATEWAY_INTERFACE = 'CGI/1.1'
> HTTPS = 'on'
> HTTP_ACCEPT = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
> HTTP_ACCEPT_ENCODING = 'gzip,deflate'
> HTTP_CONNECTION = 'Keep-Alive'
> HTTP_HOST = 'mailman.ardc.net <http://mailman.ardc.net/>'
> HTTP_USER_AGENT = 'Mozilla/5.0 (compatible; BLEXBot/1.0; +http://webmeup-crawler.com/ <http://webmeup-crawler.com/>)'
> PATH = '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
> PATH_INFO = '/accounts/fedora/login/'
> QUERY_STRING = 'process=login&next=/mailman3/hyperkitty/list/44net(a)mailman.ampr.org <mailto:process=login&next=/mailman3/hyperkitty/list/44net@mailman.ampr.org>/message/O5Z2YZBJZXFPH2ACAORN6BST7B2S3M3P/'
> REMOTE_ADDR = '157.90.177.212'
> REMOTE_PORT = '63384'
> REQUEST_METHOD = 'GET'
> REQUEST_SCHEME = 'https'
> REQUEST_URI = '/mailman3/accounts/fedora/login/?process=login&next=/mailman3/hyperkitty/list/44net(a)mailman.ampr.org <mailto:mailman3/accounts/fedora/login/?process=login&next=/mailman3/hyperkitty/list/44net@mailman.ampr.org>/message/O5Z2YZBJZXFPH2ACAORN6BST7B2S3M3P/'
> SCRIPT_FILENAME = 'proxy:uwsgi://localhost//accounts/fedora/login/' <uwsgi://localhost//accounts/fedora/login/'>
> SCRIPT_NAME = '/mailman3'
> SERVER_ADDR = '44.1.1.29'
> SERVER_ADMIN = 'postmaster(a)ardc.net <mailto:postmaster@ardc.net>'
> SERVER_NAME = 'mailman.ardc.net <http://mailman.ardc.net/>'
> SERVER_PORT = '443'
> SERVER_PROTOCOL = 'HTTP/1.1'
> SERVER_SIGNATURE = '<address>Apache/2.4.53 (Debian) Server at mailman.ardc.net <http://mailman.ardc.net/> Port 443</address>\n'
> SERVER_SOFTWARE = 'Apache/2.4.53 (Debian)'
> SSL_TLS_SNI = 'mailman.ardc.net <http://mailman.ardc.net/>'
> uwsgi.core = 1
> uwsgi.node = b'mailman'
> uwsgi.version = b'2.0.19.1-debian'
> wsgi.errors = <_io.TextIOWrapper name=2 mode='w' encoding='UTF-8'>
> wsgi.file_wrapper = ''
> wsgi.input = <uwsgi._Input object at 0x7f8e0b4a0410>
> wsgi.multiprocess = False
> wsgi.multithread = True
> wsgi.run_once = False
> wsgi.url_scheme = 'https'
> wsgi.version = '(1, 0)'
>
> Settings:
> Using settings module settings
> ABSOLUTE_URL_OVERRIDES = {}
> ACCOUNT_AUTHENTICATION_METHOD = 'username_email'
> ACCOUNT_DEFAULT_HTTP_PROTOCOL = 'https'
> ACCOUNT_EMAIL_REQUIRED = True
> ACCOUNT_EMAIL_VERIFICATION = 'mandatory'
> ACCOUNT_UNIQUE_EMAIL = True
> ADMINS = "(('Mailman Suite Admin', 'postmaster(a)ardc.net <mailto:postmaster@ardc.net>'),)"
> ALLOWED_HOSTS = ['*']
> APPEND_SLASH = True
> AUTHENTICATION_BACKENDS = "('django.contrib.auth.backends.ModelBackend', 'allauth.account.auth_backends.AuthenticationBackend')"
> AUTH_PASSWORD_VALIDATORS = '********************'
> AUTH_USER_MODEL = 'auth.User'
> BASE_DIR = '/usr/share/mailman3-web'
> CACHES = {'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'}}
> CACHE_MIDDLEWARE_ALIAS = 'default'
> CACHE_MIDDLEWARE_KEY_PREFIX = '********************'
> CACHE_MIDDLEWARE_SECONDS = 600
> COMPRESSORS = {'css': 'compressor.css.CssCompressor', 'js': 'compressor.js.JsCompressor'}
> COMPRESS_CACHEABLE_PRECOMPILERS = '()'
> COMPRESS_CACHE_BACKEND = 'default'
> COMPRESS_CACHE_KEY_FUNCTION = '********************'
> COMPRESS_CLEAN_CSS_ARGUMENTS = ''
> COMPRESS_CLEAN_CSS_BINARY = 'cleancss'
> COMPRESS_CLOSURE_COMPILER_ARGUMENTS = ''
> COMPRESS_CLOSURE_COMPILER_BINARY = 'java -jar compiler.jar'
> COMPRESS_CSS_HASHING_METHOD = 'mtime'
> COMPRESS_DATA_URI_MAX_SIZE = 1024
> COMPRESS_DEBUG_TOGGLE = None
> COMPRESS_ENABLED = True
> COMPRESS_FILTERS = {'css': ['compressor.filters.css_default.CssAbsoluteFilter'], 'js': ['compressor.filters.jsmin.JSMinFilter']}
> COMPRESS_JINJA2_GET_ENVIRONMENT = <function CompressorConf.JINJA2_GET_ENVIRONMENT at 0x7f8e17d7a670>
> COMPRESS_MINT_DELAY = 30
> COMPRESS_MTIME_DELAY = 10
> COMPRESS_OFFLINE = True
> COMPRESS_OFFLINE_CONTEXT = {'STATIC_URL': '/mailman3/static/'}
> COMPRESS_OFFLINE_MANIFEST = 'manifest.json'
> COMPRESS_OFFLINE_TIMEOUT = 31536000
> COMPRESS_OUTPUT_DIR = 'CACHE'
> COMPRESS_PARSER = 'compressor.parser.AutoSelectParser'
> COMPRESS_PRECOMPILERS = '()'
> COMPRESS_REBUILD_TIMEOUT = 2592000
> COMPRESS_ROOT = '/var/lib/mailman3/web/static'
> COMPRESS_STORAGE = 'compressor.storage.CompressorFileStorage'
> COMPRESS_TEMPLATE_FILTER_CONTEXT = {'STATIC_URL': '/mailman3/static/'}
> COMPRESS_URL = '/mailman3/static/'
> COMPRESS_URL_PLACEHOLDER = '/__compressor_url_placeholder__/'
> COMPRESS_VERBOSE = False
> COMPRESS_YUGLIFY_BINARY = 'yuglify'
> COMPRESS_YUGLIFY_CSS_ARGUMENTS = '--terminal'
> COMPRESS_YUGLIFY_JS_ARGUMENTS = '--terminal'
> COMPRESS_YUI_BINARY = 'java -jar yuicompressor.jar'
> COMPRESS_YUI_CSS_ARGUMENTS = ''
> COMPRESS_YUI_JS_ARGUMENTS = ''
> CSRF_COOKIE_AGE = 31449600
> CSRF_COOKIE_DOMAIN = None
> CSRF_COOKIE_HTTPONLY = False
> CSRF_COOKIE_NAME = 'csrftoken'
> CSRF_COOKIE_PATH = '/'
> CSRF_COOKIE_SAMESITE = 'Lax'
> CSRF_COOKIE_SECURE = False
> CSRF_FAILURE_VIEW = 'django.views.csrf.csrf_failure'
> CSRF_HEADER_NAME = 'HTTP_X_CSRFTOKEN'
> CSRF_TRUSTED_ORIGINS = []
> CSRF_USE_SESSIONS = False
> DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql', 'NAME': 'mailman', 'USER': 'mailman', 'PASSWORD': '********************', 'HOST': ‘X.X.X.X', 'PORT': '', 'OPTIONS': {'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", 'charset': 'utf8mb4'}, 'ATOMIC_REQUESTS': False, 'AUTOCOMMIT': True, 'CONN_MAX_AGE': 0, 'TIME_ZONE': None, 'TEST': {'CHARSET': None, 'COLLATION': None, 'NAME': None, 'MIRROR': None}}}
> DATABASE_ROUTERS = []
> DATA_UPLOAD_MAX_MEMORY_SIZE = 2621440
> DATA_UPLOAD_MAX_NUMBER_FIELDS = 1000
> DATETIME_FORMAT = 'N j, Y, P'
> DATETIME_INPUT_FORMATS = ['%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M:%S.%f', '%Y-%m-%d %H:%M', '%Y-%m-%d', '%m/%d/%Y %H:%M:%S', '%m/%d/%Y %H:%M:%S.%f', '%m/%d/%Y %H:%M', '%m/%d/%Y', '%m/%d/%y %H:%M:%S', '%m/%d/%y %H:%M:%S.%f', '%m/%d/%y %H:%M', '%m/%d/%y']
> DATE_FORMAT = 'N j, Y'
> DATE_INPUT_FORMATS = ['%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', '%b %d %Y', '%b %d, %Y', '%d %b %Y', '%d %b, %Y', '%B %d %Y', '%B %d, %Y', '%d %B %Y', '%d %B, %Y']
> DEBUG = False
> DEBUG_PROPAGATE_EXCEPTIONS = False
> DECIMAL_SEPARATOR = '.'
> DEFAULT_CHARSET = 'utf-8'
> DEFAULT_CONTENT_TYPE = 'text/html'
> DEFAULT_EXCEPTION_REPORTER_FILTER = 'django.views.debug.SafeExceptionReporterFilter'
> DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
> DEFAULT_FROM_EMAIL = 'postorius(a)mailman.ardc.net <mailto:postorius@mailman.ardc.net>'
> DEFAULT_INDEX_TABLESPACE = ''
> DEFAULT_TABLESPACE = ''
> DISALLOWED_USER_AGENTS = []
> EMAILNAME = 'mailman.ardc.net <http://mailman.ardc.net/>'
> EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
> EMAIL_HOST = 'localhost'
> EMAIL_HOST_PASSWORD = '********************'
> EMAIL_HOST_USER = ''
> EMAIL_PORT = 25
> EMAIL_SSL_CERTFILE = None
> EMAIL_SSL_KEYFILE = '********************'
> EMAIL_SUBJECT_PREFIX = '[Django] '
> EMAIL_TIMEOUT = None
> EMAIL_USE_LOCALTIME = False
> EMAIL_USE_SSL = False
> EMAIL_USE_TLS = False
> FILE_CHARSET = 'utf-8'
> FILE_UPLOAD_DIRECTORY_PERMISSIONS = None
> FILE_UPLOAD_HANDLERS = ['django.core.files.uploadhandler.MemoryFileUploadHandler', 'django.core.files.uploadhandler.TemporaryFileUploadHandler']
> FILE_UPLOAD_MAX_MEMORY_SIZE = 2621440
> FILE_UPLOAD_PERMISSIONS = None
> FILE_UPLOAD_TEMP_DIR = None
> FILTER_VHOST = False
> FIRST_DAY_OF_WEEK = 0
> FIXTURE_DIRS = []
> FORCE_SCRIPT_NAME = None
> FORMAT_MODULE_PATH = None
> FORM_RENDERER = 'django.forms.renderers.DjangoTemplates'
> HAYSTACK_CONNECTIONS = {'default': {'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine', 'PATH': '/var/lib/mailman3/web/fulltext_index'}}
> HOSTNAME = 'localhost.local'
> IGNORABLE_404_URLS = []
> INSTALLED_APPS = "('hyperkitty', 'postorius', 'django_mailman3', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', 'django_gravatar', 'compressor', 'haystack', 'django_extensions', 'django_q', 'allauth', 'allauth.account', 'allauth.socialaccount', 'django_mailman3.lib.auth.fedora')"
> INTERNAL_IPS = []
> LANGUAGES = [('af', 'Afrikaans'), ('ar', 'Arabic'), ('ast', 'Asturian'), ('az', 'Azerbaijani'), ('bg', 'Bulgarian'), ('be', 'Belarusian'), ('bn', 'Bengali'), ('br', 'Breton'), ('bs', 'Bosnian'), ('ca', 'Catalan'), ('cs', 'Czech'), ('cy', 'Welsh'), ('da', 'Danish'), ('de', 'German'), ('dsb', 'Lower Sorbian'), ('el', 'Greek'), ('en', 'English'), ('en-au', 'Australian English'), ('en-gb', 'British English'), ('eo', 'Esperanto'), ('es', 'Spanish'), ('es-ar', 'Argentinian Spanish'), ('es-co', 'Colombian Spanish'), ('es-mx', 'Mexican Spanish'), ('es-ni', 'Nicaraguan Spanish'), ('es-ve', 'Venezuelan Spanish'), ('et', 'Estonian'), ('eu', 'Basque'), ('fa', 'Persian'), ('fi', 'Finnish'), ('fr', 'French'), ('fy', 'Frisian'), ('ga', 'Irish'), ('gd', 'Scottish Gaelic'), ('gl', 'Galician'), ('he', 'Hebrew'), ('hi', 'Hindi'), ('hr', 'Croatian'), ('hsb', 'Upper Sorbian'), ('hu', 'Hungarian'), ('hy', 'Armenian'), ('ia', 'Interlingua'), ('id', 'Indonesian'), ('io', 'Ido'), ('is', 'Icelandic'), ('it', 'Italian'), ('ja', 'Japanese'), ('ka', 'Georgian'), ('kab', 'Kabyle'), ('kk', 'Kazakh'), ('km', 'Khmer'), ('kn', 'Kannada'), ('ko', 'Korean'), ('lb', 'Luxembourgish'), ('lt', 'Lithuanian'), ('lv', 'Latvian'), ('mk', 'Macedonian'), ('ml', 'Malayalam'), ('mn', 'Mongolian'), ('mr', 'Marathi'), ('my', 'Burmese'), ('nb', 'Norwegian Bokmål'), ('ne', 'Nepali'), ('nl', 'Dutch'), ('nn', 'Norwegian Nynorsk'), ('os', 'Ossetic'), ('pa', 'Punjabi'), ('pl', 'Polish'), ('pt', 'Portuguese'), ('pt-br', 'Brazilian Portuguese'), ('ro', 'Romanian'), ('ru', 'Russian'), ('sk', 'Slovak'), ('sl', 'Slovenian'), ('sq', 'Albanian'), ('sr', 'Serbian'), ('sr-latn', 'Serbian Latin'), ('sv', 'Swedish'), ('sw', 'Swahili'), ('ta', 'Tamil'), ('te', 'Telugu'), ('th', 'Thai'), ('tr', 'Turkish'), ('tt', 'Tatar'), ('udm', 'Udmurt'), ('uk', 'Ukrainian'), ('ur', 'Urdu'), ('vi', 'Vietnamese'), ('zh-hans', 'Simplified Chinese'), ('zh-hant', 'Traditional Chinese')]
> LANGUAGES_BIDI = ['he', 'ar', 'fa', 'ur']
> LANGUAGE_CODE = 'en-us'
> LANGUAGE_COOKIE_AGE = None
> LANGUAGE_COOKIE_DOMAIN = None
> LANGUAGE_COOKIE_NAME = 'django_language'
> LANGUAGE_COOKIE_PATH = '/'
> LOCALE_PATHS = []
> LOGGING = {'version': 1, 'disable_existing_loggers': False, 'filters': {'require_debug_false': {'()': 'django.utils.log.RequireDebugFalse'}}, 'handlers': {'mail_admins': {'level': 'ERROR', 'filters': ['require_debug_false'], 'class': 'django.utils.log.AdminEmailHandler'}, 'file': {'level': 'INFO', 'class': 'logging.handlers.RotatingFileHandler', 'filename': '/var/log/mailman3/web/mailman-web.log', 'formatter': 'verbose'}, 'console': {'class': 'logging.StreamHandler', 'formatter': 'simple'}}, 'loggers': {'django.request': {'handlers': ['mail_admins', 'file'], 'level': 'INFO', 'propagate': True}, 'django': {'handlers': ['file'], 'level': 'INFO', 'propagate': True}, 'hyperkitty': {'handlers': ['file'], 'level': 'INFO', 'propagate': True}, 'postorius': {'handlers': ['file'], 'level': 'INFO', 'propagate': True}}, 'formatters': {'verbose': {'format': '%(levelname)s %(asctime)s %(process)d %(name)s %(message)s'}, 'simple': {'format': '%(levelname)s %(message)s'}}}
> LOGGING_CONFIG = 'logging.config.dictConfig'
> LOGIN_REDIRECT_URL = 'list_index'
> LOGIN_URL = 'account_login'
> LOGOUT_REDIRECT_URL = None
> LOGOUT_URL = 'account_logout'
> MAILMAN_ARCHIVER_FROM = "('127.0.0.1', '::1', '10.4.16.129', '44.1.1.29')"
> MAILMAN_ARCHIVER_KEY = '********************'
> MAILMAN_REST_API_PASS = '********************'
> MAILMAN_REST_API_URL = '********************'
> MAILMAN_REST_API_USER = '********************'
> MANAGERS = []
> MEDIA_ROOT = ''
> MEDIA_URL = ''
> MESSAGE_STORAGE = 'django.contrib.messages.storage.fallback.FallbackStorage'
> MESSAGE_TAGS = {40: 'danger'}
> MIDDLEWARE = "('django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.locale.LocaleMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.security.SecurityMiddleware', 'django_mailman3.middleware.TimezoneMiddleware', 'postorius.middleware.PostoriusMiddleware')"
> MIGRATION_MODULES = {}
> MONTH_DAY_FORMAT = 'F j'
> NUMBER_GROUPING = 0
> PASSWORD_HASHERS = '********************'
> PASSWORD_RESET_TIMEOUT_DAYS = '********************'
> POSTORIUS_TEMPLATE_BASE_URL = 'http://localhost/mailman3/ <http://localhost/mailman3/>'
> PREPEND_WWW = False
> Q_CLUSTER = {'timeout': 300, 'save_limit': 100, 'orm': 'default', 'poll': 5}
> ROOT_URLCONF = 'urls'
> SECRET_KEY = '********************'
> SECURE_BROWSER_XSS_FILTER = False
> SECURE_CONTENT_TYPE_NOSNIFF = False
> SECURE_HSTS_INCLUDE_SUBDOMAINS = False
> SECURE_HSTS_PRELOAD = False
> SECURE_HSTS_SECONDS = 0
> SECURE_PROXY_SSL_HEADER = None
> SECURE_REDIRECT_EXEMPT = []
> SECURE_SSL_HOST = None
> SECURE_SSL_REDIRECT = False
> SERVER_EMAIL = 'root(a)mailman.ardc.net <mailto:root@mailman.ardc.net>'
> SESSION_CACHE_ALIAS = 'default'
> SESSION_COOKIE_AGE = 1209600
> SESSION_COOKIE_DOMAIN = None
> SESSION_COOKIE_HTTPONLY = True
> SESSION_COOKIE_NAME = 'sessionid'
> SESSION_COOKIE_PATH = '/'
> SESSION_COOKIE_SAMESITE = 'Lax'
> SESSION_COOKIE_SECURE = False
> SESSION_ENGINE = 'django.contrib.sessions.backends.db'
> SESSION_EXPIRE_AT_BROWSER_CLOSE = False
> SESSION_FILE_PATH = None
> SESSION_SAVE_EVERY_REQUEST = False
> SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
> SETTINGS_MODULE = 'settings'
> SHORT_DATETIME_FORMAT = 'm/d/Y P'
> SHORT_DATE_FORMAT = 'm/d/Y'
> SIGNING_BACKEND = 'django.core.signing.TimestampSigner'
> SILENCED_SYSTEM_CHECKS = []
> SITE_ID = 1
> SOCIALACCOUNT_PROVIDERS = {}
> STATICFILES_DIRS = '()'
> STATICFILES_FINDERS = "('django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 'compressor.finders.CompressorFinder')"
> STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'
> STATIC_ROOT = '/var/lib/mailman3/web/static'
> STATIC_URL = '/mailman3/static/'
> TEMPLATES = [{'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': {'context_processors': ['django.template.context_processors.debug', 'django.template.context_processors.i18n', 'django.template.context_processors.media', 'django.template.context_processors.static', 'django.template.context_processors.tz', 'django.template.context_processors.csrf', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', 'django_mailman3.context_processors.common', 'hyperkitty.context_processors.common', 'postorius.context_processors.postorius']}}]
> TEST_NON_SERIALIZED_APPS = []
> TEST_RUNNER = 'django.test.runner.DiscoverRunner'
> THOUSAND_SEPARATOR = ','
> TIME_FORMAT = 'P'
> TIME_INPUT_FORMATS = ['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
> TIME_ZONE = 'UTC'
> USE_I18N = True
> USE_L10N = True
> USE_THOUSAND_SEPARATOR = False
> USE_TZ = True
> USE_X_FORWARDED_HOST = True
> USE_X_FORWARDED_PORT = False
> WSGI_APPLICATION = 'wsgi.application'
> X_FRAME_OPTIONS = 'SAMEORIGIN'
> YEAR_MONTH_FORMAT = 'F Y’
>
>
>
>
> _______________________________________________
> Mailman-users mailing list -- mailman-users(a)mailman3.org
> To unsubscribe send an email to mailman-users-leave(a)mailman3.org
> https://lists.mailman3.org/mailman3/lists/mailman-users.mailman3.org/
3 years, 3 months

Re: Archive Policy not reflecting in Hyperkitty
by Nathan Dixon
Update: I have manage to get this working.
I had to delete all images in docker that were anything to do with mailman.
Docker-compose rm didn't clean up enough stuff.
Once there were no other mailman docker images, I then ran
$ docker pull quay.io/maxking/mailman-web:0.2
$ docker pull quay.io/maxking/mailman-core:0.2
And docker-compose up didn't show any error messages relating to Hyperkitty
this time and the archive policy is reflecting in Hyperkitty as it shows in
Postorius.
Thanks for your help Abhilash!
Regards,
On Mon, 13 May 2019 at 12:28, Nathan Dixon <nathan.dixon(a)evadon.com> wrote:
> Hi,
> I have removed the docker images and pulled the version tagged as 0.2.
>
> $ docker pull quay.io/maxking/mailman-web:0.2
> $ docker pull quay.io/maxking/mailman-core:0.2
>
> Unfortunately I am still getting the error message when trying to run the
> sync_mailman job manually:
>
> # python3 manage.py runjob sync_mailman
>
> Also running docker-compose up (without -d) I am seeing these errors for
> each of the lists that currently exist:
>
> database_1 | ERROR: null value in column "description" violates
> not-null constraint
> database_1 | DETAIL: Failing row contains (2,
> <listname>@<domain>.com, OMA-COM, null, [OMA-COM], 1, 2019-02-25
> 13:30:03.868072+00, <listuri>).
> database_1 | STATEMENT: UPDATE "hyperkitty_mailinglist" SET "name" =
> '<listname>@<domain>.com', "list_id" = '<listuri>', "display_name" =
> '<LISTNAME>', "description" = NULL, "subject_prefix" = '[<LISTNAME>]',
> "archive_policy" = 1, "created_at" =
> '2019-02-25T13:30:03.868072+00:00'::timestamptz WHERE
> "hyperkitty_mailinglist"."id" = 2
> database_1 | ERROR: null value in column "description" violates
> not-null constraint
>
> All of the lists do have description that I can see in the Postorius
> interface.
>
> Thanks
>
> On Tue, 7 May 2019 at 16:06, Abhilash Raj <maxking(a)asynchronous.in> wrote:
>
>> Are you using images with "rolling" tags?
>>
>> If yes, you should try to switch to "0.2" tag and the new release will be
>> tagged with the same one.
>>
>> To update, you can do:
>>
>> $ docker pull ...
>> $ docker pull ..
>>
>> $ docker-compose stop
>> $ docker-compose rm
>> $ docker-compose up -d
>>
>> This should basically get you up and running with the new image you
>> pulled.
>>
>>
>> --
>> thanks,
>> Abhilash Raj (maxking)
>>
>>
>>
>
> --
>
> *Nathan Dixon* MEng
> Senior Software Architect
> m: +44 (0)7402 690311
>
> t: +44 (0)20 81231252
> e: nathan.dixon(a)evadon.com
> w: www.evadon.com
>
> This e-mail and any attachments are confidential and may be protected by
> legal, professional or other privilege. If you are not the intended
> recipient you should not store it, copy it, re-transmit it, use it or
> disclose its contents, but should return it to the sender immediately and
> delete your copy from your system. The views expressed are those of the
> sender and not necessarily those of Evadon. Please note that whilst we scan
> all e-mails for viruses we cannot guarantee that any e-mail is virus-free.
> Please be advised that we expressly reserve the right to monitor email
> content for the purposes of ensuring compliance with legal requirements and
> company policies and your sending to, or receiving from, us of any email
> constitutes your agreement to these terms.
>
>
> Evadon Dynamics Limited, registered in England No. 09494097. Registered
> Office: Electric Works, Sheffield Digital Campus, 3 Concourse Way, Sheffield,
> S1 2BJ
>
--
*Nathan Dixon* MEng
Senior Software Architect
m: +44 (0)7402 690311
t: +44 (0)20 81231252
e: nathan.dixon(a)evadon.com
w: www.evadon.com
This e-mail and any attachments are confidential and may be protected by
legal, professional or other privilege. If you are not the intended
recipient you should not store it, copy it, re-transmit it, use it or
disclose its contents, but should return it to the sender immediately and
delete your copy from your system. The views expressed are those of the
sender and not necessarily those of Evadon. Please note that whilst we scan
all e-mails for viruses we cannot guarantee that any e-mail is virus-free.
Please be advised that we expressly reserve the right to monitor email
content for the purposes of ensuring compliance with legal requirements and
company policies and your sending to, or receiving from, us of any email
constitutes your agreement to these terms.
Evadon Dynamics Limited, registered in England No. 09494097. Registered
Office: Electric Works, Sheffield Digital Campus, 3 Concourse Way, Sheffield,
S1 2BJ
6 years, 5 months

Re: Bulk delivery status change?
by Stephen Daniel
If I run
>>> for mlist in getUtility(IListManager):
... print(mlist)
...
<mailing list "testlist1(a)chapelwoodhoadev.org" at 0x7f83f593fba8>
I get only one list. Permissions? Where are the other lists?
On Sun, Nov 10, 2024 at 11:52 AM Stephen Daniel <swd(a)pobox.com> wrote:
> OK. Ran the script. No errors while running it, but when I look at the
> users through Postorius GUI, they still show as 'Disabled by Bounces'
>
> ??
>
> On Sun, Nov 10, 2024 at 11:42 AM Stephen Daniel <swd(a)pobox.com> wrote:
>
>> Thanks all! I will use these pronto.
>>
>> On Sun, Nov 10, 2024 at 11:42 AM Mark Sapiro <mark(a)msapiro.net> wrote:
>>
>>> On 11/10/24 08:34, Odhiambo Washington via Mailman-users wrote:
>>> > On Sun, Nov 10, 2024 at 7:16 PM Stephen Daniel <swd(a)pobox.com> wrote:
>>> >
>>> >> Mistakes were made, and for while every single outbound email bounced.
>>> >> I've fixed the mistakes, but now in my largest and most active email
>>> list,
>>> >> every single user's delivery status is "Disabled by Bounces".
>>> >>
>>> >> Is there a way to bulk fix this? Or do I have to go into each user,
>>> one at
>>> >> a time, and fix them?
>>> >
>>> > Please see this thread:
>>> >
>>> https://lists.mailman3.org/archives/list/mailman-users@mailman3.org/message…
>>>
>>> The script in that post does all lists. For a single list see
>>>
>>> https://lists.mailman3.org/archives/list/mailman-users@mailman3.org/message…
>>> but note that the command line
>>> ```
>>> $ shell -l list(a)example.com
>>> ```
>>> should be
>>> ```
>>> $ mailman shell -l list(a)example.com
>>> ```
>>>
>>> --
>>> Mark Sapiro <mark(a)msapiro.net> The highway is for gamblers,
>>> San Francisco Bay Area, California better use your sense - B. Dylan
>>>
>>> _______________________________________________
>>> Mailman-users mailing list -- mailman-users(a)mailman3.org
>>> To unsubscribe send an email to mailman-users-leave(a)mailman3.org
>>> https://lists.mailman3.org/mailman3/lists/mailman-users.mailman3.org/
>>> Archived at:
>>> https://lists.mailman3.org/archives/list/mailman-users@mailman3.org/message…
>>>
>>> This message sent to swd(a)pobox.com
>>>
>>
11 months, 1 week

Re: makemigrations --merge error after Debian upgrade
by Mihai Moldovan
* On 4/16/25 01:04, Sam Darwin via Mailman-users wrote:
> "Virtualenv Installation, recommended for Production"
>
> It's recommended for production.
>
> I've followed that method. If someone does this, they may never encounter
> or bump into any files from the "distro packaging (specifically in Debian
> and Ubuntu)" .
True, and that's fine. :)
> Which means they're missing out on this particular idea about the mailman
> wrapper. The script is small enough it can be described in the docs.
>
> Let's try a grep inside mailman-suite-docs:
>
> grep -r -i wrapper *
>
> no relevant results.
They are small scripts, but describing them in the documentation is problematic
because they depend on user names and file system locations, which in turn are
distro- or even system-dependent. (Just as an example, some distros use www-data
as the web service user, which is needed for the hyperkitty and postorius
integrations, while other distros use wwwrun and even others just plain www or
something else entirely.)
Providing such wrappers as part of venv or the upstream repository is hence not
possible.
This said, nobody prevents you from creating such wrappers for use with your
venv installation tailored to your system either, just make sure that you write
them up correctly. :)
Also, as is often the way, the documentation could probably be also improved.
For instance, the migration documentation says:
> This, and in general all, mailman commands should be run as the Mailman
> user and not as root. Running some of these commands as root can create
> files owned by root that can’t be read by the Mailman user.
But it doesn't explicitly tell you how to do this. Naturally, as a system
administrator installing, maintaining and migrating mailman instances, you
should probably know how to run a command as a specific user.
su -s /bin/sh -c "mailman ..." $LIST_USER
and
su -s /bin/sh -c "$PYTHON_BINARY $PATH_TO_MANAGE_PY ..." $WWW_USER
is probably what you want to execute commands either as the mailing list or as
the web user, with all these variables being pseudo-variables that you want to
fill in/hardcode to fit your system correctly. Putting that in the documentation
and especially educating users to not use them in a copy-and-paste manner is
difficult, though. Try that and you'll probably have an influx of requests along
the lines of "I don't have a variable called $LIST_USER, the command fails to
execute!"
Mihai
6 months

Re: Can "Pre Verified" set to yes by default?
by Stephen J. Turnbull
Hi Alan,
It occurred to me that Django template widgets are very flexible. It
may be possible to customize the template to accomplish this task. In
that case, the customized template would be kept in a place that
doesn't get overwritten in an upgrade, reducing the maintenance cost
(unless either Postorius or Django changes the template in a way that
seems unlikely to me). I'll try to take a look at that over the
holiday break -- that has the advantage that I just document how we
did it for you, and tell any future requests to RTFM and DIY. ;-)
Alan So writes:
> I can say that it is not purely a technical issue in an
> organization that whether system admin should maintain a few minor
> changes that are not in the main branch.
Sure, we understand that. I'd be interested to hear from business
users and university users if they would like this particular default
to be configurable. It's very easy to do as a one-off, if there is
substantial demand we *can* do it, and later say to people who want
similar changes that it's on them to demonstrate they have enough
demand on their side for another one-off, just as was done for this
one.
> Due to massive customization made to previous Mailman 2
> installation by some student helpers which made it very difficult
> to be upgraded nearly 20 years ago, we tend not to repeat this
> pattern when we upgrade to Mailman 3 a few years ago.
I agree, you need to be disciplined about what changes you are willing
to develop and maintain. This one seemed to me to be over that bar,
especially since you can put it in and not suffer too greatly if it
gets reverted in a upgrade and the maintainers don't notice.
> After all, it is just one of the many suggestions that you
> received. I respect the decision of the core team. If the core
> team consider that this feature is low priority, it is fine not to
> implement it.
Unless I see a lot of demand, I think as a one-off I don't want to
implement it in list_forms.py, but rather let occasional admins do it
on their sites if they want it that bad. But GSoC is coming up again;
maybe a student would be willing to take on a generic "pwn all the
defaults" project next summer.
Steve
2 years, 10 months

Re: Counter-intuitive header filter processing
by Mark Sapiro
On 09/18/2018 01:04 PM, Jonas Meurer wrote:
>
> Maybe then the description for chain "accept" in postorius needs to be
> adjusted. Currently it says "Accept immediately (bypass other rules)".
> This gives the impression, that it will overrule the default action.
Yes, I agree it's confusing.
> A related followup question: what configuration is recommended for an
> announcement list where only specific senders (e.g. sender(a)example.org)
> should be allowed to post and mail from all (other) subscribers should
> be rejected?
>
> The only way I see to achieve this currently is:
>
> * Set default action for member posts to "Default processing"
> * Add a header filter to accept "sender(a)example.org"
> * Add a header filter to reject ".*"
>
> In my eyes, that's very counter-intuitive and cumbersome to configure.
> But maybe I just missed a more obvious and elegant solution to achieve
> the same?
The way to do that is to set the default action for member posts to
Reject and set Member Options -> Administration options -> Moderation
for the authorized posters to Accept or Default processing as desired.
However, this allows anyone to post by spoofing an authorized address.
To avoid that, leave everyone's Moderation setting at List default and
post using "pre-approval" (see
<https://mailman.readthedocs.io/en/latest/src/mailman/rules/docs/approved.ht…>.
The downside of this is it requires the poster to send a cleartext
password in a header or body line of the post. It will be removed from
the post delivered to list members, but sending it in cleartext in an
email may be an issue. We will eventually do something with PGP
signatures instead, but that isn't here yet.
> And one more comment: if I make the list an "anonymous list" (i.e. "hide
> the sender of a message, replacing it with the list address"), then
> header filters for the "from" header don't work any longer. That's kind
> of unexpected as well. I would have expected mailman to process the
> header filters at reading the incoming mail, not after rewriting headers
> of the outgoing mail?
Your expectation is correct. All the applicable rules are applied to the
incoming message before any message alterations such as anonymizing are
applied. Possibly you were confused because some other rule's action
took precedence over your header rule.
--
Mark Sapiro <mark(a)msapiro.net> The highway is for gamblers,
San Francisco Bay Area, California better use your sense - B. Dylan
7 years, 1 month

Re: MM2 to MM3 on debian 10
by Gelpi Andrea
Il 27/04/20 18:59, Mark Sapiro ha scritto:
> On 4/27/20 8:26 AM, Gelpi Andrea wrote:
>> Hi, on a debian 10 with MM3 I'm trying to migrate form some old MM2
>> mailing lists. I know that not all can work.
>>
>> In my old lists I have email and regular expressions in
>> reject_these_nonmembers and discard_these_nonmembers
>>
>> After importing the list all these email are in non member list.
>>
>> All these email have Delivery status enabled.
>
>
> Delivery status is not relevant for non-members and only has to do with
> receiving list posts in any case.
>
> What version of Mailman core is this? There have been changes in
> `mailman import21` that may affect this, but an address in
> `reject_these_nonmembers` should be imported as a non-member with a
> moderation action of `reject` and similarly for `discard`.
>
> Note that regexps in *_these_nonmembers should be imported into the MM 3
> legacy *_these_nonmembers attributes. Some older versions of import21
> also imported non-regexp addresses here, but that was wrong.
>
Mailman V 3.2.1
Python V 3.7.3
Postorius V 1.3.2
Hiperkitty V 1.2.2
Yes reject_these_nonmembers has a moderation action of 'reject' and the
some for discard.
>
>> Does this mean that all of them will receive any message sent to the list?
>> The moderation rule is correct, but if I understood correct Delivery
>> status should be disabled.
>
>
> Delivery status is irrelevant for non-members. Only members are
> candidates for delivery.
>
Ok, but will non-members receive the list posts or only members will?
>
>> For migration I followed this link
>> https://docs.mailman3.org/en/latest/migration.html
>>
>> To migrate archives it states to run
>>
>> python manage.py hyperkitty ...
>>
>> I cant' find a manage.py on debian 10
>
>
> manage.py is a Django generic term for the Django admin command. You
> probably want something called django-admin or similar.
>
Yes in debain 10 exists django-admin.
Now I need to understand how to use it. It asks me to load a configuration.
>
>> A search shows the only /usr/share/mailman3-web/manage.py exists.
>>
>> Is there any documentation specific for debian?
>
> That would be up to Debian.
>
--
Gelpi ing. Andrea
--------------------------------------------------------------
It took the computing power of three C-64s to fly to the Moon.
It takes a 486 to run Windows 95. Something is wrong here.
--------------------------------------------------------------
5 years, 5 months

Re: Archive Policy not reflecting in Hyperkitty
by Abhilash Raj
On Fri, May 3, 2019, at 8:38 AM, Nathan Dixon wrote:
> So the issue I am seeing is that when I set a lists archive policy to
> prviate, it isn't reflecting that in Hyperkitty.
>
> I am running the docker installation of Mailman, postorius and hyperkitty.
> So I go into the docker instance of mailman-core and run this:
>
> python3 manage.py shell from hyperkitty.models.mailinglist import
> MailingList MailingList.objects.all().values_list('name', 'archive_policy')
>
> And all my lists are showing '2', regardless of how I set the mailing list
> archive policy.
>
> This might be a duplicate of
> https://lists.mailman3.org/archives/list/mailman-users@mailman3.org/thread/…
>
> Am I missing something in my install? Or is this a bug?
It can take upto an hour for this change to reflect in Hyperkitty. Did you wait
for that long?
This happens because Hyperkitty stores it's own data, and queries Mailman
Core periodically to fetch updates every hour. In future, we might be able to
do this in more realtime fashion by using an event based pub/sub model. But,
we are not there yet.
>
> Many thanks for your attention,
>
> --
>
> *Nathan Dixon* MEng
> Senior Software Architect
> m: +44 (0)7402 690311
>
> t: +44 (0)20 81231252
> e: nathan.dixon(a)evadon.com
> w: www.evadon.com
>
> This e-mail and any attachments are confidential and may be protected by
> legal, professional or other privilege. If you are not the intended
> recipient you should not store it, copy it, re-transmit it, use it or
> disclose its contents, but should return it to the sender immediately and
> delete your copy from your system. The views expressed are those of the
> sender and not necessarily those of Evadon. Please note that whilst we scan
> all e-mails for viruses we cannot guarantee that any e-mail is virus-free.
> Please be advised that we expressly reserve the right to monitor email
> content for the purposes of ensuring compliance with legal requirements and
> company policies and your sending to, or receiving from, us of any email
> constitutes your agreement to these terms.
>
>
> Evadon Dynamics Limited, registered in England No. 09494097. Registered
> Office: Electric Works, Sheffield Digital Campus, 3 Concourse Way, Sheffield,
> S1 2BJ
> _______________________________________________
> Mailman-users mailing list -- mailman-users(a)mailman3.org
> To unsubscribe send an email to mailman-users-leave(a)mailman3.org
> https://lists.mailman3.org/mailman3/lists/mailman-users.mailman3.org/
>
--
thanks,
Abhilash Raj (maxking)
6 years, 5 months

Re: Migrating Mailman 3 lists
by Andrew Hodgson
Abhilash Raj wrote:
>On Mon, Apr 27, 2020, at 9:05 AM, Andrew Hodgson wrote:
[Moving Mailman to new server]
>> I did this the other week, the difference I think we've got here is
>> that I migrated the whole instance (Mailman Core's var files plus
>> complete Postgresql database) over to the new server rather than
>> trying to add the lists to an existing setup, which I couldn't work
>> out either which is what prompted me to complete the server migration
>> before adding more lists.
>> The only issue I ran into was not copying the Mailman Core var files
>> to the new server, this actually gave me a bit of trouble later on as
>> firstly Mailman doesn't create the lists directory which is what I was
>> checking with Exim for list existence, and also I had an issue where I
>> was missing a moderated message from the messages directory which
>> stopped the admin interface from displaying for that list.
>var/ directory does store some state for Mailman, specifically queued messages. Optionally, also templates. Directory structure is something that could be fixed with this issue[1], but given that the messages are still stored on the >filesystem instead of database, you'd need to move var/ directory too.
I would say that the var directory structure is essential to keep if possible between servers. I don't really want to fix the issue where I couldn't access a list because of old pending messages that were no longer available. I fixed it in the end by creating pickles with the same name, and then just deleting the messages from the web interface. The problem was happening because Postorius was trying to get the list of held messages to show on the admin interface, this caused Mailman REST interface to throw an exception.
I was going to post on here but figured it out in the end.
Another issue though stemming from this is that when I was moving the data across I had several messages in the var/messages directory structure and my incorrect assumption was that they were old held messages which weren't deleted. There were around 60 messages in that folder structure and I actually only needed to recover 2 of them to get the list on track, I forgot to check that the user had cleared their held messages. Even now when I deleted the fake messages I put there in the web interface, the files are still now on the server in that structure.
Andrew.
5 years, 5 months