diff --git a/etc/config.py.example b/etc/config.py.example
index 9c02e6220eba28e46892afe3c92af960ed968e39..15d6230448b43e6bd81ca60807b76eefbca6d84e 100644
--- a/etc/config.py.example
+++ b/etc/config.py.example
@@ -80,6 +80,9 @@ REG_MAX_PER_MINUTE = 10
 # Jak dlouho vydrží tokeny používané při registraci a změnách e-mailu [min]
 REG_TOKEN_VALIDITY = 10
 
+# Jak dlouho si pamatujeme e-mailovou nedoručenku [min]
+DSN_EXPIRATION = 30 * 1440
+
 # Aktuální ročník MO
 CURRENT_YEAR = 71
 
diff --git a/mo/util_dsn.py b/mo/util_dsn.py
index b442e2561d4656561cdd89a710c473a8901eed6c..64fe8cd7a760abf451e64ad5a44fa09947c9c4f4 100644
--- a/mo/util_dsn.py
+++ b/mo/util_dsn.py
@@ -1,7 +1,13 @@
 # Utility na práci s mailovými nedoručenkami
 
+from datetime import timedelta
+from sqlalchemy import select
 from typing import Optional
 
+import mo
+import mo.config as config
+import mo.db as db
+
 
 dsn_explanation = {
     '4.2.2': 'schránka je plná',
@@ -26,3 +32,19 @@ def format_dsn_status(status: Optional[str]) -> str:
             return f'{status} – {explain}'
         else:
             return status
+
+
+def expire_dsns() -> None:
+    expiration = getattr(config, 'DSN_EXPIRATION', None)
+    if expiration is None:
+        return
+
+    sess = db.get_session()
+    conn = sess.connection()
+    user_table = db.User.__table__
+    dsn_table = db.EmailDSN.__table__
+    conn.execute(dsn_table.delete()
+                 .where(dsn_table.c.arrived_at < mo.now - timedelta(days=expiration))
+                 .where(dsn_table.c.dsn_id.not_in(select(user_table.c.dsn_id))))
+
+    sess.commit()
diff --git a/mo/web/__init__.py b/mo/web/__init__.py
index 743333c79bc389f15b9655525802e092e545f316..f8ccc040f8ed3cb984b97e144e9190f76faef56d 100644
--- a/mo/web/__init__.py
+++ b/mo/web/__init__.py
@@ -23,6 +23,7 @@ import mo.jobs.submit
 import mo.rights
 import mo.users
 import mo.util
+import mo.util_dsn
 
 
 class MOFlask(Flask):
@@ -210,11 +211,13 @@ app.before_request(init_request)
 #    - projdeme joby pro případ, že by se ztratil signál
 #    - expirujeme zastaralé joby
 #    - expirujeme zastaralé registrační tokeny
+#    - expirujeme zastaralé nedoručenky
 def collect_garbage() -> None:
     mo.now = mo.util.get_now()
     mo.jobs.submit.check_broken_submits()
     mo.jobs.process_jobs()
     mo.users.expire_reg_requests()
+    mo.util_dsn.expire_dsns()
 
 
 @app.cli.command('gc')