#!/usr/bin/env python3 """Write the deterministic Maildir used for docs/performance.md. The mailbox mixes HTML newsletters, short HTML notifications and plain-text conversations, some with PDF attachments, dated over the last 60 days. Serve it with any IMAP server that reads Maildir (the measurements used Dovecot). scripts/generate-benchmark-mailbox.py ~/bench/Maildir """ from __future__ import annotations import argparse import email.utils import os import random import time from email.message import EmailMessage from pathlib import Path SENDERS = [ ("Ana Ruiz", "ana@northwind.example"), ("Ben Ortiz", "ben@contoso.example"), ("Chloe Martin", "chloe@fabrikam.example"), ("Dmitri Ivanov", "dmitri@adatum.example"), ("Elena Rossi", "elena@litware.example"), ("Farah Khan", "farah@proseware.example"), ("Gwen Lee", "gwen@tailspin.example"), ("Hugo Silva", "hugo@wingtip.example"), ] LISTS = [ ("Rust Weekly", "news@rustweekly.example"), ("Design Digest", "hello@designdigest.example"), ("Cloud Status", "status@cloudhost.example"), ("Shop Deals", "deals@shop.example"), ("Dev Events", "events@devconf.example"), ("Bank Notices", "notice@bank.example"), ] WORDS = ( "release roadmap invoice meeting sprint review design budget travel report " "draft summary feedback launch update contract quarterly agenda notes metrics " "deploy migration customer support partner workshop hiring planning" ).split() class Generator: def __init__(self, seed: int, now: float) -> None: self.rng = random.Random(seed) self.now = now def sentence(self, words: int = 12) -> str: return " ".join(self.rng.choice(WORDS) for _ in range(words)).capitalize() + "." def paragraph(self, sentences: int = 4) -> str: return " ".join(self.sentence(self.rng.randint(8, 18)) for _ in range(sentences)) def newsletter(self, title: str) -> str: stories = [] for index in range(self.rng.randint(4, 9)): stories.append(f"""

{self.sentence(6)}

{self.paragraph(3)}

Read more """) return f"""
{''.join(stories)}
""" def notification(self) -> str: return f"""

{self.sentence(5)}

{self.paragraph(2)}

View details

""" def message(self, index: int) -> tuple[float, bytes, str]: kind = self.rng.random() sent = self.now - self.rng.uniform(0, 60 * 86400) message = EmailMessage() message["Date"] = email.utils.formatdate(sent) message["To"] = "Test User " message["Message-ID"] = f"" if kind < 0.45: name, address = self.rng.choice(LISTS) message["From"] = f"{name} <{address}>" message["Subject"] = f"{name}: {self.sentence(5)[:-1]}" message["List-Unsubscribe"] = "" message.set_content(self.paragraph(6)) message.add_alternative(self.newsletter(name), subtype="html") elif kind < 0.65: name, address = self.rng.choice(LISTS) message["From"] = f"{name} <{address}>" message["Subject"] = self.sentence(6)[:-1] message.set_content(self.paragraph(2)) message.add_alternative(self.notification(), subtype="html") else: name, address = self.rng.choice(SENDERS) message["From"] = f"{name} <{address}>" subject = self.sentence(5)[:-1] if self.rng.random() < 0.35 and index > 10: parent = self.rng.randint(0, index - 1) message["In-Reply-To"] = f"" message["References"] = f"" subject = "Re: " + subject message["Subject"] = subject first = name.split()[0] message.set_content(f"Hi,\n\n{self.paragraph(3)}\n\n{self.paragraph(2)}\n\nThanks,\n{first}\n") if self.rng.random() < 0.12: size = self.rng.randint(20_000, 120_000) data = bytes(self.rng.getrandbits(8) for _ in range(size)) message.add_attachment( data, maintype="application", subtype="pdf", filename=f"{self.rng.choice(WORDS)}-{index}.pdf" ) flags = "S" if self.rng.random() < 0.8 else "" if self.rng.random() < 0.05: flags = "F" + flags return sent, message.as_bytes(), flags def write_folder(self, folder: Path, first: int, count: int) -> None: for name in ("cur", "new", "tmp"): (folder / name).mkdir(parents=True, exist_ok=True) for index in range(first, first + count): sent, raw, flags = self.message(index) path = folder / "cur" / f"{int(sent)}.M{index}P1.flectar-bench,S={len(raw)}:2,{flags}" path.write_bytes(raw) # Maildir servers report the file time as the received date. os.utime(path, (sent, sent)) def main() -> int: parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument("maildir", type=Path, help="Maildir to create; must not contain mail yet") parser.add_argument("--inbox", type=int, default=600, help="Inbox messages (default 600)") parser.add_argument("--seed", type=int, default=20261103) args = parser.parse_args() if args.inbox < 1 or any((args.maildir / "cur").glob("*")): parser.error("use an empty Maildir and at least one Inbox message") # The email package draws MIME boundaries from the global generator. random.seed(args.seed) generator = Generator(args.seed, time.time()) archive, sent = args.inbox // 3, args.inbox // 10 generator.write_folder(args.maildir, 0, args.inbox) generator.write_folder(args.maildir / ".Archive", args.inbox, archive) generator.write_folder(args.maildir / ".Sent", args.inbox + archive, sent) for folder in (".Drafts", ".Trash", ".Junk"): for name in ("cur", "new", "tmp"): (args.maildir / folder / name).mkdir(parents=True, exist_ok=True) print(f"Wrote {args.inbox + archive + sent} messages to {args.maildir}") return 0 if __name__ == "__main__": raise SystemExit(main())