diff --git a/mo/users.py b/mo/users.py
index bc5494b4754ce8d9e9ae075cf0e162fa5b7e07c5..685112af5559960b4f41b7f315f153753352895e 100644
--- a/mo/users.py
+++ b/mo/users.py
@@ -293,6 +293,32 @@ def email_check_domain(domain: str):
     raise mo.CheckError(f'Doména {domain} nepřijímá poštu')
 
 
+def email_or_synthesize(addr: Optional[str], first_name: Optional[str], last_name: Optional[str], grade: Optional[str], school: Optional[db.Place]) -> str:
+    """
+    Pokud e-mailová adresa není zadaná, nějakou si vymyslíme podle jména, školy a ročníku.
+    Předpokládá, že parametry, které nejsou None, mají syntaxi zkontrolovanou.
+    """
+
+    if addr:
+        return addr
+
+    if not first_name or not last_name or not grade or school is None:
+        raise mo.CheckError('Pokud není zadaná e-mailová adresa, je nutné uvést jméno, příjmení, školu a ročník')
+
+    # Spočítáme ročník MO, kdy daný účastník chodil do 1. třídy
+    norm_grade = mo.util.normalize_grade(grade)
+    if norm_grade < 0:
+        ref_year = 0
+    else:
+        ref_year = config.CURRENT_YEAR - norm_grade + 1
+
+    x = mo.util.asciify(f'{school.place_id}-{ref_year}.{first_name}.{last_name}')
+    x = re.sub(r'\s+', '-', x)
+    x = re.sub(r'[^0-9a-zA-Z.-]', "", x)
+
+    return normalize_email(x + '@nomail')
+
+
 def normalize_email(addr: str, check_existence: bool = False, make_unique_nomail: bool = False) -> str:
     if make_unique_nomail and addr == '@nomail':
         addr = base64.b32encode(secrets.token_bytes(10)).decode('US-ASCII').lower() + '@nomail'