
Hereby I am sharing the full settings.py file.
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) import os
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
# SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = 'change-this-on-your-production-server'
# SECURITY WARNING: don't run with debug turned on in production! DEBUG = False
ADMINS = ( ('Mailman Suite Admin', 'root@localhost'), )
SITE_ID = 1
# Hosts/domain names that are valid for this site; required if DEBUG is False # See https://docs.djangoproject.com/en/1.8/ref/settings/#allowed-hosts ALLOWED_HOSTS = [ "localhost", # Archiving API from Mailman, keep it. # "lists.your-domain.org", # Add here all production URLs you may have. ]
# Mailman API credentials MAILMAN_REST_API_URL = 'http://localhost:8001' MAILMAN_REST_API_USER = 'restadmin' MAILMAN_REST_API_PASS = 'restpass' MAILMAN_ARCHIVER_KEY = 'SecretArchiverAPIKey' MAILMAN_ARCHIVER_FROM = ('127.0.0.1', '::1')# Application definition
INSTALLED_APPS = ( 'hyperkitty', 'postorius', 'django_mailman3', # Uncomment the next line to enable the admin: 'django.contrib.admin', # Uncomment the next line to enable admin documentation: # 'django.contrib.admindocs', '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', # 'allauth.socialaccount.providers.openid', # 'allauth.socialaccount.providers.github', # 'allauth.socialaccount.providers.gitlab', # 'allauth.socialaccount.providers.google', # 'allauth.socialaccount.providers.facebook', # 'allauth.socialaccount.providers.twitter', # 'allauth.socialaccount.providers.stackexchange', )
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', )
ROOT_URLCONF = 'urls'
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', ], }, }, ]
WSGI_APPLICATION = 'wsgi.application' # Database # https://docs.djangoproject.com/en/1.8/ref/settings/#databases
DATABASES = { 'default': { # Use 'sqlite3', 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 'ENGINE': 'django.db.backends.postgresql_psycopg2', # DB name or path to database file if using sqlite3. 'NAME': 'mailman3web', # The following settings are not used with sqlite3: 'USER': 'mailmansuite', 'PASSWORD': 'mmpass', # HOST: empty for localhost through domain sockets or '127.0.0.1' for # localhost through TCP. 'HOST': '', # PORT: set to empty string for default. 'PORT': '', # OPTIONS: for mysql engine only, do not use with other engines. # 'OPTIONS': {'charset': 'utf8mb4'} # Enable utf8 4-byte encodings. } # Example for PostgreSQL (recommanded for production): #'default': { # 'ENGINE': 'django.db.backends.postgresql_psycopg2', # 'NAME': 'database_name', # 'USER': 'database_user', # 'PASSWORD': 'database_password', # 'HOST': 'localhost', #} }
# If you're behind a proxy, use the X-Forwarded-Host header # See https://docs.djangoproject.com/en/1.8/ref/settings/#use-x-forwarded-host USE_X_FORWARDED_HOST = True
# And if your proxy does your SSL encoding for you, set SECURE_PROXY_SSL_HEADER # https://docs.djangoproject.com/en/1.8/ref/settings/#secure-proxy-ssl-header # SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') # SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_SCHEME', 'https')
# Other security settings # SECURE_SSL_REDIRECT = True # If you set SECURE_SSL_REDIRECT to True, make sure the SECURE_REDIRECT_EXEMPT # contains at least this line: # SECURE_REDIRECT_EXEMPT = [ # "archives/api/mailman/.*", # Request from Mailman. # ]# SESSION_COOKIE_SECURE = True # SECURE_CONTENT_TYPE_NOSNIFF = True # SECURE_BROWSER_XSS_FILTER = True # CSRF_COOKIE_SECURE = True # CSRF_COOKIE_HTTPONLY = True # X_FRAME_OPTIONS = 'DENY'
# Password validation # https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ]# Internationalization # https://docs.djangoproject.com/en/1.8/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.8/howto/static-files/
# Absolute path to the directory static files should be collected to. # Don't put anything in this directory yourself; store your static files # in apps' "static/" subdirectories and in STATICFILES_DIRS. # Example: "/var/www/example.com/static/" STATIC_ROOT = '/var/lib/mailman3/web/static'
# URL prefix for static files. # Example: "http://example.com/static/", "http://static.example.com/" STATIC_URL = '/mailman3/static/'
# Additional locations of static files STATICFILES_DIRS = ( # Put strings here, like "/home/html/static" or "C:/www/django/static". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. # BASE_DIR + '/static/', )
# List of finder classes that know how to find static files in # various locations.STATICFILES_FINDERS = ( 'django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder', # 'django.contrib.staticfiles.finders.DefaultStorageFinder', 'compressor.finders.CompressorFinder', )
# Django 1.6+ defaults to a JSON serializer, but it won't work with # django-openid, see # https://bugs.launchpad.net/django-openid-auth/+bug/1252826 SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
LOGIN_URL = 'account_login' LOGIN_REDIRECT_URL = 'list_index' LOGOUT_URL = 'account_logout'
HOSTNAME = 'localhost.local'
# If you enable internal authentication, this is the address that the emails # will appear to be coming from. Make sure you set a valid domain name, # otherwise the emails may get rejected. # https://docs.djangoproject.com/en/1.8/ref/settings/#default-from-email # DEFAULT_FROM_EMAIL = "mailing-lists@you-domain.org" DEFAULT_FROM_EMAIL = 'postorius@{}'.format(HOSTNAME)
# If you enable email reporting for error messages, this is where those emails # will appear to be coming from. Make sure you set a valid domain name, # otherwise the emails may get rejected. # https://docs.djangoproject.com/en/1.8/ref/settings/#std:setting-SERVER_EMAIL # SERVER_EMAIL = 'root@your-domain.org' SERVER_EMAIL = 'root@{}'.format(HOSTNAME)
# Change this when you have a real email backend EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# Compatibility with Bootstrap 3 from django.contrib.messages import constants as messages # flake8: noqa MESSAGE_TAGS = { messages.ERROR: 'danger' } # # Social auth # AUTHENTICATION_BACKENDS = ( 'django.contrib.auth.backends.ModelBackend', 'allauth.account.auth_backends.AuthenticationBackend', )
# Django Allauth ACCOUNT_AUTHENTICATION_METHOD = "username_email" ACCOUNT_EMAIL_REQUIRED = True ACCOUNT_EMAIL_VERIFICATION = "mandatory" # You probably want https in production, but this is a dev setup file ACCOUNT_DEFAULT_HTTP_PROTOCOL = "https" ACCOUNT_UNIQUE_EMAIL = True
SOCIALACCOUNT_PROVIDERS = { #'openid': { # 'SERVERS': [ # dict(id='yahoo', # name='Yahoo', # openid_url='http://me.yahoo.com'), # ], #}, #'google': { # 'SCOPE': ['profile', 'email'], # 'AUTH_PARAMS': {'access_type': 'online'}, #}, #'facebook': { # 'METHOD': 'oauth2', # 'SCOPE': ['email'], # 'FIELDS': [ # 'email', # 'name', # 'first_name', # 'last_name', # 'locale', # 'timezone', # ], # 'VERSION': 'v2.4', #}, } # # Gravatar # https://github.com/twaddington/django-gravatar # # Gravatar base url. # GRAVATAR_URL = 'http://cdn.libravatar.org/' # Gravatar base secure https url. # GRAVATAR_SECURE_URL = 'https://seccdn.libravatar.org/' # Gravatar size in pixels. # GRAVATAR_DEFAULT_SIZE = '80' # An image url or one of the following: 'mm', 'identicon', 'monsterid', # 'wavatar', 'retro'. # GRAVATAR_DEFAULT_IMAGE = 'mm' # One of the following: 'g', 'pg', 'r', 'x'. # GRAVATAR_DEFAULT_RATING = 'g' # True to use https by default, False for plain http. # GRAVATAR_DEFAULT_SECURE = True
# # django-compressor # https://pypi.python.org/pypi/django_compressor # #COMPRESS_PRECOMPILERS = ( # ('text/less', 'lessc {infile} {outfile}'), # ('text/x-scss', 'sassc -t compressed {infile} {outfile}'), # ('text/x-sass', 'sassc -t compressed {infile} {outfile}'), #) # On a production setup, setting COMPRESS_OFFLINE to True will bring a # significant performance improvement, as CSS files will not need to be # recompiled on each requests. It means running an additional "compress" # management command after each code upgrade. # http://django-compressor.readthedocs.io/en/latest/usage/#offline-compression # COMPRESS_OFFLINE = True
# Needed for debug mode # INTERNAL_IPS = ('127.0.0.1',)
# # Full-text search engine #HAYSTACK_CONNECTIONS = { 'default': { 'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine', 'PATH': '/var/lib/mailman3/web/fulltext_index', # You can also use the Xapian engine, it's faster and more accurate, # but requires another library. # http://django-haystack.readthedocs.io/en/v2.4.1/installing_search_engines.ht... # Example configuration for Xapian: #'ENGINE': 'xapian_backend.XapianEngine' }, }
# # Asynchronous tasks # Q_CLUSTER = { 'timeout': 300, 'save_limit': 100, 'orm': 'default', 'poll': 5, }# A sample logging configuration. The only tangible logging # performed by this configuration is to send an email to # the site admins on every HTTP 500 error when DEBUG=False. # See http://docs.djangoproject.com/en/dev/topics/logging for # more details on how to customize your logging configuration. 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', #'class': 'logging.handlers.WatchedFileHandler', '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' }, }, #'root': { # 'handlers': ['file'], # 'level': 'INFO', #}, } if DEBUG == True: EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend' EMAIL_FILE_PATH = os.path.join(BASE_DIR, 'emails')
# # HyperKitty-specific #
# Only display mailing-lists from the same virtual host as the webserver FILTER_VHOST = False
POSTORIUS_TEMPLATE_BASE_URL = 'http://localhost:8000'
try: from settings_local import * except ImportError: pass
-----Original Message----- From: Stephen <steve@turnbull.jp> To: nirmal <nirmal@iitm.ac.in> Cc: mailman-users <mailman-users@mailman3.org> Date: Friday, 26 September 2025 1:15 PM IST Subject: [MM3-users] Reg Archive Inactive Status
nirmal--- via Mailman-users writes:
Sep 24 10:45:43 2025 (187698) HyperKitty failure on http://list1.iitm.ac.in/hyperkitty/api/mailman/urls: <html><title>Forbidden</title><body> <h1>Access is forbidden</h1><p>Please check the IP addresses assigned to MAILMAN_ARCHIVER_FROM in the settings file. </p></body></html> (403)
You need to ensure the IP address of list1.iitm.ac.in is in the MAILMAN_ARCHIVER_FROM list in your Django settings.
I have also ensured that the IP Address of list1.iitm.ac.in is in the Mailman_Archiver_From List in settings. But still not working. Please help.
Please be more specific than "not working", as much as possible. In this case, copy the setting from your settings.py file and paste it in the email. Always describe the error message. If it's identical to the previous one except for the timestamp and server process, just saying "error message is the same" is OK. If it's not, any small difference could be a clue, and you should copy and paste it.
Check the syntax of the assignment to MAILMAN_ARCHIVER_FROM in settings.py. The variable name must be all uppercase. The assignment must use '-', and the value should be a Python sequence[1] of strings, like this:
MAILMAN_ARCHIVER_FROM = ('127.0.0.1', '::1')
Even if there is only one IP, I suspect the parentheses are required, and the single entry *must* be followed by a comma, like this:
MAILMAN_ARCHIVER_FROM = ('127.0.0.1',)
If your setting is correct, check your webserver's (Apache, nginx, etc) configuration for access restrictions. Many Mailman installation guides assume localhost and provide examples restricting access to localhost.
Finally, if no configured access restriction applies, there should be a corresponding entry in the webserver's access log. Check that the source IP is what you expect.
Footnotes: [1] If you are an experienced Python programmer, I believe you can use any sequence syntax you are comfortable with. Tuples will definitely work because that's the test configuration we use. :-)
-- GNU Mailman consultant (installation, migration, customization) Sirius Open Source https://www.siriusopensource.com/ Software systems consulting in Europe, North America, and Japan