From c9a2d14ed784a439cfdad0a232a611a436c77940 Mon Sep 17 00:00:00 2001
From: Kevin Rocker <me@kevinrocker.com>
Date: Wed, 24 Jun 2026 15:25:21 +0200
Subject: [PATCH] Serve per-month mbox downloads with a unique filename

The monthly mbox download view streamed responses with only a
Content-type header and no Content-Disposition, so browsers derived the
saved filename from the URL. Every month of a list shares the same name
bar the extension, so downloading several months produced
pgsql-hackers.mbox, pgsql-hackers(1).mbox, ... rather than distinct,
identifiable files.

Add an optional filename argument to _build_mbox() that emits a
Content-Disposition: attachment header, and have the per-month mbox()
view pass listname.YYYYMM.mbox (matching the existing URL scheme), so
each month downloads under a distinct, descriptive name.
---
 django/archives/mailarchives/views.py | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/django/archives/mailarchives/views.py b/django/archives/mailarchives/views.py
index 5d7e321..fbc9731 100644
--- a/django/archives/mailarchives/views.py
+++ b/django/archives/mailarchives/views.py
@@ -676,7 +676,7 @@ def message_raw(request, msgid):
     return r
 
 
-def _build_mbox(query, params, msgid=None):
+def _build_mbox(query, params, msgid=None, filename=None):
     connection.ensure_connection()
 
     # Rawmsg is not in the django model, so we have to query it separately
@@ -710,6 +710,8 @@ def _build_mbox(query, params, msgid=None):
 
     r = StreamingHttpResponse(_message_stream(firstmsg))
     r['Content-type'] = 'application/mbox'
+    if filename:
+        r['Content-Disposition'] = 'attachment; filename="%s"' % filename
     return r
 
 
@@ -755,7 +757,11 @@ def mbox(request, listname, listname2, mboxyear, mboxmonth):
     else:
         # Just return the whole thing
         query = query.replace('%%%', '')
-    return _build_mbox(query, params)
+    # Set a per-list, per-month filename (matching the URL scheme,
+    # listname.YYYYMM) so downloads don't all collide on the same name.
+    return _build_mbox(
+        query, params,
+        filename='%s.%04d%02d.mbox' % (listname, mboxyear, mboxmonth))
 
 
 @transaction.atomic
-- 
2.54.0

