Просмотр исходного кода

rename GenEmail -> Alias, gen_email to alias whenever possible

Son NK 5 лет назад
Родитель
Сommit
4f281bdbbb
33 измененных файлов с 335 добавлено и 357 удалено
  1. 35 35
      app/api/views/alias.py
  2. 9 9
      app/api/views/alias_options.py
  3. 5 5
      app/api/views/new_custom_alias.py
  4. 4 4
      app/api/views/new_random_alias.py
  5. 1 1
      app/api/views/user_info.py
  6. 3 3
      app/dashboard/templates/dashboard/alias_contact_manager.html
  7. 18 18
      app/dashboard/templates/dashboard/index.html
  8. 3 3
      app/dashboard/templates/dashboard/refused_email.html
  9. 9 12
      app/dashboard/views/alias_contact_manager.py
  10. 10 10
      app/dashboard/views/alias_log.py
  11. 5 9
      app/dashboard/views/custom_alias.py
  12. 2 2
      app/dashboard/views/domain_detail.py
  13. 52 61
      app/dashboard/views/index.py
  14. 2 2
      app/dashboard/views/mailbox_detail.py
  15. 3 5
      app/dashboard/views/setting.py
  16. 10 10
      app/dashboard/views/unsubscribe.py
  17. 6 6
      app/email_utils.py
  18. 23 25
      app/models.py
  19. 10 10
      app/oauth/views/authorize.py
  20. 12 12
      cron.py
  21. 2 2
      docs/upgrade.md
  22. 64 66
      email_handler.py
  23. 3 3
      server.py
  24. 2 2
      templates/emails/transactional/automatic-disable-alias.html
  25. 2 2
      templates/emails/transactional/automatic-disable-alias.txt
  26. 2 2
      templates/emails/transactional/bounced-email.html
  27. 1 1
      templates/emails/transactional/bounced-email.txt
  28. 19 19
      tests/api/test_alias.py
  29. 3 3
      tests/api/test_alias_options.py
  30. 4 4
      tests/api/test_new_custom_alias.py
  31. 3 3
      tests/api/test_new_random_alias.py
  32. 1 1
      tests/api/test_user_info.py
  33. 7 7
      tests/test_models.py

+ 35 - 35
app/api/views/alias.py

@@ -13,7 +13,7 @@ from app.dashboard.views.index import get_alias_info, AliasInfo
 from app.extensions import db
 from app.log import LOG
 from app.models import EmailLog
-from app.models import GenEmail, Contact
+from app.models import Alias, Contact
 from app.utils import random_string
 
 
@@ -43,23 +43,23 @@ def get_aliases():
     except (ValueError, TypeError):
         return jsonify(error="page_id must be provided in request query"), 400
 
-    aliases: [AliasInfo] = get_alias_info(user, page_id=page_id)
+    alias_infos: [AliasInfo] = get_alias_info(user, page_id=page_id)
 
     return (
         jsonify(
             aliases=[
                 {
-                    "id": alias.id,
-                    "email": alias.gen_email.email,
-                    "creation_date": alias.gen_email.created_at.format(),
-                    "creation_timestamp": alias.gen_email.created_at.timestamp,
-                    "nb_forward": alias.nb_forward,
-                    "nb_block": alias.nb_blocked,
-                    "nb_reply": alias.nb_reply,
-                    "enabled": alias.gen_email.enabled,
-                    "note": alias.note,
+                    "id": alias_info.id,
+                    "email": alias_info.alias.email,
+                    "creation_date": alias_info.alias.created_at.format(),
+                    "creation_timestamp": alias_info.alias.created_at.timestamp,
+                    "nb_forward": alias_info.nb_forward,
+                    "nb_block": alias_info.nb_blocked,
+                    "nb_reply": alias_info.nb_reply,
+                    "enabled": alias_info.alias.enabled,
+                    "note": alias_info.note,
                 }
-                for alias in aliases
+                for alias_info in alias_infos
             ]
         ),
         200,
@@ -79,12 +79,12 @@ def delete_alias(alias_id):
 
     """
     user = g.user
-    gen_email = GenEmail.get(alias_id)
+    alias = Alias.get(alias_id)
 
-    if gen_email.user_id != user.id:
+    if alias.user_id != user.id:
         return jsonify(error="Forbidden"), 403
 
-    GenEmail.delete(alias_id)
+    Alias.delete(alias_id)
     db.session.commit()
 
     return jsonify(deleted=True), 200
@@ -105,15 +105,15 @@ def toggle_alias(alias_id):
 
     """
     user = g.user
-    gen_email: GenEmail = GenEmail.get(alias_id)
+    alias: Alias = Alias.get(alias_id)
 
-    if gen_email.user_id != user.id:
+    if alias.user_id != user.id:
         return jsonify(error="Forbidden"), 403
 
-    gen_email.enabled = not gen_email.enabled
+    alias.enabled = not alias.enabled
     db.session.commit()
 
-    return jsonify(enabled=gen_email.enabled), 200
+    return jsonify(enabled=alias.enabled), 200
 
 
 @api_bp.route("/aliases/<int:alias_id>/activities")
@@ -138,12 +138,12 @@ def get_alias_activities(alias_id):
     except (ValueError, TypeError):
         return jsonify(error="page_id must be provided in request query"), 400
 
-    gen_email: GenEmail = GenEmail.get(alias_id)
+    alias: Alias = Alias.get(alias_id)
 
-    if gen_email.user_id != user.id:
+    if alias.user_id != user.id:
         return jsonify(error="Forbidden"), 403
 
-    alias_logs = get_alias_log(gen_email, page_id)
+    alias_logs = get_alias_log(alias, page_id)
 
     activities = []
     for alias_log in alias_logs:
@@ -187,13 +187,13 @@ def update_alias(alias_id):
         return jsonify(error="request body cannot be empty"), 400
 
     user = g.user
-    gen_email: GenEmail = GenEmail.get(alias_id)
+    alias: Alias = Alias.get(alias_id)
 
-    if gen_email.user_id != user.id:
+    if alias.user_id != user.id:
         return jsonify(error="Forbidden"), 403
 
     new_note = data.get("note")
-    gen_email.note = new_note
+    alias.note = new_note
     db.session.commit()
 
     return jsonify(note=new_note), 200
@@ -218,9 +218,9 @@ def serialize_contact(fe: Contact) -> dict:
     return res
 
 
-def get_alias_contacts(gen_email, page_id: int) -> [dict]:
+def get_alias_contacts(alias, page_id: int) -> [dict]:
     q = (
-        Contact.query.filter_by(gen_email_id=gen_email.id)
+        Contact.query.filter_by(gen_email_id=alias.id)
         .order_by(Contact.id.desc())
         .limit(PAGE_LIMIT)
         .offset(page_id * PAGE_LIMIT)
@@ -257,12 +257,12 @@ def get_alias_contacts_route(alias_id):
     except (ValueError, TypeError):
         return jsonify(error="page_id must be provided in request query"), 400
 
-    gen_email: GenEmail = GenEmail.get(alias_id)
+    alias: Alias = Alias.get(alias_id)
 
-    if gen_email.user_id != user.id:
+    if alias.user_id != user.id:
         return jsonify(error="Forbidden"), 403
 
-    contacts = get_alias_contacts(gen_email, page_id)
+    contacts = get_alias_contacts(alias, page_id)
 
     return jsonify(contacts=contacts), 200
 
@@ -287,9 +287,9 @@ def create_contact_route(alias_id):
         return jsonify(error="request body cannot be empty"), 400
 
     user = g.user
-    gen_email: GenEmail = GenEmail.get(alias_id)
+    alias: Alias = Alias.get(alias_id)
 
-    if gen_email.user_id != user.id:
+    if alias.user_id != user.id:
         return jsonify(error="Forbidden"), 403
 
     contact_email = data.get("contact")
@@ -305,17 +305,17 @@ def create_contact_route(alias_id):
     _, website_email = parseaddr(contact_email)
 
     # already been added
-    if Contact.get_by(gen_email_id=gen_email.id, website_email=website_email):
+    if Contact.get_by(gen_email_id=alias.id, website_email=website_email):
         return jsonify(error="Contact already added"), 409
 
     contact = Contact.create(
-        gen_email_id=gen_email.id,
+        gen_email_id=alias.id,
         website_email=website_email,
         website_from=contact_email,
         reply_email=reply_email,
     )
 
-    LOG.d("create reverse-alias for %s %s", contact_email, gen_email)
+    LOG.d("create reverse-alias for %s %s", contact_email, alias)
     db.session.commit()
 
     return jsonify(**serialize_contact(contact)), 201

+ 9 - 9
app/api/views/alias_options.py

@@ -6,7 +6,7 @@ from app.api.base import api_bp, verify_api_key
 from app.config import ALIAS_DOMAINS, DISABLE_ALIAS_SUFFIX
 from app.extensions import db
 from app.log import LOG
-from app.models import AliasUsedOn, GenEmail, User
+from app.models import AliasUsedOn, Alias, User
 from app.utils import convert_to_id, random_word
 
 
@@ -31,7 +31,7 @@ def options():
     hostname = request.args.get("hostname")
 
     ret = {
-        "existing": [ge.email for ge in GenEmail.query.filter_by(user_id=user.id)],
+        "existing": [ge.email for ge in Alias.query.filter_by(user_id=user.id)],
         "can_create_custom": user.can_create_new_alias(),
     }
 
@@ -39,10 +39,10 @@ def options():
     if hostname:
         # put the latest used alias first
         q = (
-            db.session.query(AliasUsedOn, GenEmail, User)
+            db.session.query(AliasUsedOn, Alias, User)
             .filter(
-                AliasUsedOn.gen_email_id == GenEmail.id,
-                GenEmail.user_id == user.id,
+                AliasUsedOn.gen_email_id == Alias.id,
+                Alias.user_id == user.id,
                 AliasUsedOn.hostname == hostname,
             )
             .order_by(desc(AliasUsedOn.created_at))
@@ -111,7 +111,7 @@ def options_v2():
 
     ret = {
         "existing": [
-            ge.email for ge in GenEmail.query.filter_by(user_id=user.id, enabled=True)
+            ge.email for ge in Alias.query.filter_by(user_id=user.id, enabled=True)
         ],
         "can_create": user.can_create_new_alias(),
         "suffixes": [],
@@ -122,10 +122,10 @@ def options_v2():
     if hostname:
         # put the latest used alias first
         q = (
-            db.session.query(AliasUsedOn, GenEmail, User)
+            db.session.query(AliasUsedOn, Alias, User)
             .filter(
-                AliasUsedOn.gen_email_id == GenEmail.id,
-                GenEmail.user_id == user.id,
+                AliasUsedOn.gen_email_id == Alias.id,
+                Alias.user_id == user.id,
                 AliasUsedOn.hostname == hostname,
             )
             .order_by(desc(AliasUsedOn.created_at))

+ 5 - 5
app/api/views/new_custom_alias.py

@@ -7,7 +7,7 @@ from app.config import MAX_NB_EMAIL_FREE_PLAN, ALIAS_DOMAINS
 from app.dashboard.views.custom_alias import verify_prefix_suffix
 from app.extensions import db
 from app.log import LOG
-from app.models import GenEmail, AliasUsedOn, User, CustomDomain
+from app.models import Alias, AliasUsedOn, User, CustomDomain
 from app.utils import convert_to_id
 
 
@@ -54,11 +54,11 @@ def new_custom_alias():
         return jsonify(error="wrong alias prefix or suffix"), 400
 
     full_alias = alias_prefix + alias_suffix
-    if GenEmail.get_by(email=full_alias):
+    if Alias.get_by(email=full_alias):
         LOG.d("full alias already used %s", full_alias)
         return jsonify(error=f"alias {full_alias} already exists"), 409
 
-    gen_email = GenEmail.create(
+    alias = Alias.create(
         user_id=user.id, email=full_alias, mailbox_id=user.default_mailbox_id, note=note
     )
 
@@ -67,12 +67,12 @@ def new_custom_alias():
         if alias_domain not in ALIAS_DOMAINS:
             domain = CustomDomain.get_by(domain=alias_domain)
             LOG.d("set alias %s to domain %s", full_alias, domain)
-            gen_email.custom_domain_id = domain.id
+            alias.custom_domain_id = domain.id
 
     db.session.commit()
 
     if hostname:
-        AliasUsedOn.create(gen_email_id=gen_email.id, hostname=hostname)
+        AliasUsedOn.create(gen_email_id=alias.id, hostname=hostname)
         db.session.commit()
 
     return jsonify(alias=full_alias), 201

+ 4 - 4
app/api/views/new_random_alias.py

@@ -6,7 +6,7 @@ from app.api.base import api_bp, verify_api_key
 from app.config import MAX_NB_EMAIL_FREE_PLAN
 from app.extensions import db
 from app.log import LOG
-from app.models import GenEmail, AliasUsedOn, AliasGeneratorEnum
+from app.models import Alias, AliasUsedOn, AliasGeneratorEnum
 
 
 @api_bp.route("/alias/random/new", methods=["POST"])
@@ -47,12 +47,12 @@ def new_random_alias():
         else:
             return jsonify(error=f"{mode} must be either word or alias"), 400
 
-    gen_email = GenEmail.create_new_random(user=user, scheme=scheme, note=note)
+    alias = Alias.create_new_random(user=user, scheme=scheme, note=note)
     db.session.commit()
 
     hostname = request.args.get("hostname")
     if hostname:
-        AliasUsedOn.create(gen_email_id=gen_email.id, hostname=hostname)
+        AliasUsedOn.create(gen_email_id=alias.id, hostname=hostname)
         db.session.commit()
 
-    return jsonify(alias=gen_email.email), 201
+    return jsonify(alias=alias.email), 201

+ 1 - 1
app/api/views/user_info.py

@@ -6,7 +6,7 @@ from app.api.base import api_bp, verify_api_key
 from app.config import EMAIL_DOMAIN
 from app.extensions import db
 from app.log import LOG
-from app.models import AliasUsedOn, GenEmail, User
+from app.models import AliasUsedOn, Alias, User
 from app.utils import convert_to_id, random_word
 
 

+ 3 - 3
app/dashboard/templates/dashboard/alias_contact_manager.html

@@ -9,7 +9,7 @@
 {% block default_content %}
   <div class="page-header row">
     <h3 class="page-title col">
-      {{ alias }}
+      {{ alias.email }}
     </h3>
   </div>
 
@@ -26,8 +26,8 @@
       This might sound complicated but trust us, only the first time is a bit awkward.
     </p>
     <p>
-      {% if gen_email.mailbox_id %}
-        Make sure you send the email from the mailbox <b>{{ gen_email.mailbox.email }}</b>.
+      {% if alias.mailbox_id %}
+        Make sure you send the email from the mailbox <b>{{ alias.mailbox.email }}</b>.
         This is because only the mailbox that owns the alias can send emails from it.
       {% else %}
         Make sure you send the email from your personal email address ({{ current_user.email }}).

+ 18 - 18
app/dashboard/templates/dashboard/index.html

@@ -72,7 +72,7 @@
 
   <div class="row">
     {% for alias_info in aliases %}
-      {% set gen_email = alias_info.gen_email %}
+      {% set alias = alias_info.alias %}
 
       <div class="col-12 col-lg-6">
         <div class="card p-4 shadow-sm {% if alias_info.highlight %} highlight-row {% endif %} ">
@@ -86,14 +86,14 @@
         use it whenever possible, for example when signing up for a newsletter or creating a new account on a suspicious website 😎"
                   data-step="2"
                 {% endif %}
-                {% if gen_email.enabled %}
+                {% if alias.enabled %}
                   data-toggle="tooltip"
                   title="Copy to clipboard"
-                  data-clipboard-text="{{ gen_email.email }}"
+                  data-clipboard-text="{{ alias.email }}"
                 {% endif %}
             >
-              <span class="font-weight-bold">{{ gen_email.email }}</span>
-              {% if gen_email.enabled %}
+              <span class="font-weight-bold">{{ alias.email }}</span>
+              {% if alias.enabled %}
                 <span class="btn btn-sm btn-success copy-btn">
                   Copy
                 </span>
@@ -103,10 +103,10 @@
             <div class="col text-right">
               <form method="post">
                 <input type="hidden" name="form-name" value="switch-email-forwarding">
-                <input type="hidden" name="gen-email-id" value="{{ gen_email.id }}">
+                <input type="hidden" name="alias-id" value="{{ alias.id }}">
                 <label class="custom-switch cursor"
                        data-toggle="tooltip"
-                    {% if gen_email.enabled %}
+                    {% if alias.enabled %}
                        title="Block Alias"
                     {% else %}
                        title="Unblock Alias"
@@ -122,9 +122,9 @@
                     {% endif %}
                        style="padding-left: 0px"
                 >
-                  <input type="hidden" name="alias" class="alias" value="{{ gen_email.email }}">
+                  <input type="hidden" name="alias" class="alias" value="{{ alias.email }}">
                   <input type="checkbox" class="custom-switch-input"
-                      {{ "checked" if gen_email.enabled else "" }}>
+                      {{ "checked" if alias.enabled else "" }}>
 
                   <span class="custom-switch-indicator"></span>
                 </label>
@@ -135,7 +135,7 @@
           <hr class="my-2">
 
           <p class="small-text">
-            Created {{ gen_email.created_at | dt }}
+            Created {{ alias.created_at | dt }}
             {% if alias_info.highlight %}
               - <span class="font-weight-bold text-success small-text">New</span>
             {% endif %}
@@ -145,7 +145,7 @@
             <span class="alias-activity">{{ alias_info.nb_forward }}</span> forwards,
             <span class="alias-activity">{{ alias_info.nb_blocked }}</span> blocks,
             <span class="alias-activity">{{ alias_info.nb_reply }}</span> replies
-            <a href="{{ url_for('dashboard.alias_log', alias_id=gen_email.id) }}"
+            <a href="{{ url_for('dashboard.alias_log', alias_id=alias.id) }}"
                class="btn btn-sm btn-link">
               See All Activity &nbsp;→
             </a>
@@ -167,7 +167,7 @@
 
                 <div class="">
                   <input type="hidden" name="form-name" value="set-mailbox">
-                  <input type="hidden" name="gen-email-id" value="{{ gen_email.id }}">
+                  <input type="hidden" name="alias-id" value="{{ alias.id }}">
 
                   <button class="btn btn-sm btn-outline-info w-100">
                     Update
@@ -191,12 +191,12 @@
                     name="note"
                     class="form-control"
                     rows="2"
-                    placeholder="Alias Note.">{{ gen_email.note or "" }}</textarea>
+                    placeholder="Alias Note.">{{ alias.note or "" }}</textarea>
               </div>
 
               <div class="">
                 <input type="hidden" name="form-name" value="set-note">
-                <input type="hidden" name="gen-email-id" value="{{ gen_email.id }}">
+                <input type="hidden" name="alias-id" value="{{ alias.id }}">
 
                 <button class="btn btn-sm btn-outline-success w-100">
                   Save
@@ -207,8 +207,8 @@
 
           <div class="row mt-3">
             <div class="col">
-              {% if gen_email.enabled %}
-                <a href="{{ url_for('dashboard.alias_contact_manager', alias_id=gen_email.id) }}"
+              {% if alias.enabled %}
+                <a href="{{ url_for('dashboard.alias_contact_manager', alias_id=alias.id) }}"
                     {% if alias_info.show_intro_test_send_email %}
                    data-intro="Not only alias can receive emails, it can <em>send</em> emails too! <br><br>
                    You can add a new <em>contact</em> to for your alias here. <br><br>
@@ -228,8 +228,8 @@
             <div class="col">
               <form method="post">
                 <input type="hidden" name="form-name" value="delete-email">
-                <input type="hidden" name="gen-email-id" value="{{ gen_email.id }}">
-                <input type="hidden" name="alias" class="alias" value="{{ gen_email.email }}">
+                <input type="hidden" name="alias-id" value="{{ alias.id }}">
+                <input type="hidden" name="alias" class="alias" value="{{ alias.email }}">
 
                 <span class="delete-email btn btn-link btn-sm float-right text-danger">
                   Delete&nbsp; &nbsp;<i class="dropdown-icon fe fe-trash-2 text-danger"></i>

+ 3 - 3
app/dashboard/templates/dashboard/refused_email.html

@@ -31,7 +31,7 @@
     {% for fel in fels %}
       {% set refused_email = fel.refused_email %}
       {% set forward = fel.forward %}
-      {% set gen_email = forward.gen_email %}
+      {% set alias = forward.alias %}
 
       <div class="card p-4 shadow-sm {% if fel.id == highlight_fel_id %} highlight-row {% endif %}">
         <div class="small-text">
@@ -41,8 +41,8 @@
         From: {{ forward.website_from or forward.website_email }} <br>
 
         <span>
-          To: {{ gen_email.email }}
-          <a href='{{ url_for("dashboard.index", highlight_gen_email_id=gen_email.id) }}'
+          To: {{ alias.email }}
+          <a href='{{ url_for("dashboard.index", highlight_alias_id=alias.id) }}'
              class="btn btn-sm btn-outline-danger">Disable Alias</a>
         </span>
 

+ 9 - 12
app/dashboard/views/alias_contact_manager.py

@@ -10,7 +10,7 @@ from app.config import EMAIL_DOMAIN
 from app.dashboard.base import dashboard_bp
 from app.extensions import db
 from app.log import LOG
-from app.models import GenEmail, Contact
+from app.models import Alias, Contact
 from app.utils import random_string
 
 
@@ -51,14 +51,14 @@ class NewContactForm(FlaskForm):
 )
 @login_required
 def alias_contact_manager(alias_id, contact_id=None):
-    gen_email = GenEmail.get(alias_id)
+    alias = Alias.get(alias_id)
 
     # sanity check
-    if not gen_email:
+    if not alias:
         flash("You do not have access to this page", "warning")
         return redirect(url_for("dashboard.index"))
 
-    if gen_email.user_id != current_user.id:
+    if alias.user_id != current_user.id:
         flash("You do not have access to this page", "warning")
         return redirect(url_for("dashboard.index"))
 
@@ -80,16 +80,14 @@ def alias_contact_manager(alias_id, contact_id=None):
                 _, website_email = parseaddr(contact_email)
 
                 # already been added
-                if Contact.get_by(
-                    gen_email_id=gen_email.id, website_email=website_email
-                ):
+                if Contact.get_by(gen_email_id=alias.id, website_email=website_email):
                     flash(f"{website_email} is already added", "error")
                     return redirect(
                         url_for("dashboard.alias_contact_manager", alias_id=alias_id)
                     )
 
                 contact = Contact.create(
-                    gen_email_id=gen_email.id,
+                    gen_email_id=alias.id,
                     website_email=website_email,
                     website_from=contact_email,
                     reply_email=reply_email,
@@ -115,7 +113,7 @@ def alias_contact_manager(alias_id, contact_id=None):
                 return redirect(
                     url_for("dashboard.alias_contact_manager", alias_id=alias_id)
                 )
-            elif contact.gen_email_id != gen_email.id:
+            elif contact.gen_email_id != alias.id:
                 flash("You cannot delete reverse-alias", "warning")
                 return redirect(
                     url_for("dashboard.alias_contact_manager", alias_id=alias_id)
@@ -132,7 +130,7 @@ def alias_contact_manager(alias_id, contact_id=None):
             )
 
     # make sure highlighted contact is at array start
-    contacts = gen_email.contacts
+    contacts = alias.contacts
 
     if contact_id:
         contacts = sorted(contacts, key=lambda fe: fe.id == contact_id, reverse=True)
@@ -140,8 +138,7 @@ def alias_contact_manager(alias_id, contact_id=None):
     return render_template(
         "dashboard/alias_contact_manager.html",
         contacts=contacts,
-        alias=gen_email.email,
-        gen_email=gen_email,
+        alias=alias,
         new_contact_form=new_contact_form,
         contact_id=contact_id,
     )

+ 10 - 10
app/dashboard/views/alias_log.py

@@ -5,7 +5,7 @@ from flask_login import login_required, current_user
 from app.config import PAGE_LIMIT
 from app.dashboard.base import dashboard_bp
 from app.extensions import db
-from app.models import GenEmail, EmailLog, Contact
+from app.models import Alias, EmailLog, Contact
 
 
 class AliasLog:
@@ -29,22 +29,22 @@ class AliasLog:
 @dashboard_bp.route("/alias_log/<int:alias_id>/<int:page_id>")
 @login_required
 def alias_log(alias_id, page_id):
-    gen_email = GenEmail.get(alias_id)
+    alias = Alias.get(alias_id)
 
     # sanity check
-    if not gen_email:
+    if not alias:
         flash("You do not have access to this page", "warning")
         return redirect(url_for("dashboard.index"))
 
-    if gen_email.user_id != current_user.id:
+    if alias.user_id != current_user.id:
         flash("You do not have access to this page", "warning")
         return redirect(url_for("dashboard.index"))
 
-    logs = get_alias_log(gen_email, page_id)
+    logs = get_alias_log(alias, page_id)
     base = (
         db.session.query(Contact, EmailLog)
         .filter(Contact.id == EmailLog.contact_id)
-        .filter(Contact.gen_email_id == gen_email.id)
+        .filter(Contact.gen_email_id == alias.id)
     )
     total = base.count()
     email_forwarded = (
@@ -61,14 +61,14 @@ def alias_log(alias_id, page_id):
     return render_template("dashboard/alias_log.html", **locals())
 
 
-def get_alias_log(gen_email: GenEmail, page_id=0):
+def get_alias_log(alias: Alias, page_id=0):
     logs: [AliasLog] = []
-    mailbox = gen_email.mailbox_email()
+    mailbox = alias.mailbox_email()
 
     q = (
         db.session.query(Contact, EmailLog)
         .filter(Contact.id == EmailLog.contact_id)
-        .filter(Contact.gen_email_id == gen_email.id)
+        .filter(Contact.gen_email_id == alias.id)
         .order_by(EmailLog.id.desc())
         .limit(PAGE_LIMIT)
         .offset(page_id * PAGE_LIMIT)
@@ -78,7 +78,7 @@ def get_alias_log(gen_email: GenEmail, page_id=0):
         al = AliasLog(
             website_email=fe.website_email,
             website_from=fe.website_from,
-            alias=gen_email.email,
+            alias=alias.email,
             when=fel.created_at,
             is_reply=fel.is_reply,
             blocked=fel.blocked,

+ 5 - 9
app/dashboard/views/custom_alias.py

@@ -6,7 +6,7 @@ from app.dashboard.base import dashboard_bp
 from app.email_utils import email_belongs_to_alias_domains, get_email_domain_part
 from app.extensions import db
 from app.log import LOG
-from app.models import GenEmail, CustomDomain, DeletedAlias, Mailbox
+from app.models import Alias, CustomDomain, DeletedAlias, Mailbox
 from app.utils import convert_to_id, random_word, word_exist
 
 
@@ -60,9 +60,7 @@ def custom_alias():
         ):
             full_alias = alias_prefix + alias_suffix
 
-            if GenEmail.get_by(email=full_alias) or DeletedAlias.get_by(
-                email=full_alias
-            ):
+            if Alias.get_by(email=full_alias) or DeletedAlias.get_by(email=full_alias):
                 LOG.d("full alias already used %s", full_alias)
                 flash(
                     f"Alias {full_alias} already exists, please choose another one",
@@ -71,7 +69,7 @@ def custom_alias():
             else:
                 mailbox = Mailbox.get_by(email=mailbox_email)
 
-                gen_email = GenEmail.create(
+                alias = Alias.create(
                     user_id=current_user.id,
                     email=full_alias,
                     note=alias_note,
@@ -83,14 +81,12 @@ def custom_alias():
                 custom_domain = CustomDomain.get_by(domain=alias_domain)
                 if custom_domain:
                     LOG.d("Set alias %s domain to %s", full_alias, custom_domain)
-                    gen_email.custom_domain_id = custom_domain.id
+                    alias.custom_domain_id = custom_domain.id
 
                 db.session.commit()
                 flash(f"Alias {full_alias} has been created", "success")
 
-                return redirect(
-                    url_for("dashboard.index", highlight_gen_email_id=gen_email.id)
-                )
+                return redirect(url_for("dashboard.index", highlight_alias_id=alias.id))
         # only happen if the request has been "hacked"
         else:
             flash("something went wrong", "warning")

+ 2 - 2
app/dashboard/views/domain_detail.py

@@ -10,7 +10,7 @@ from app.dns_utils import (
     get_txt_record,
 )
 from app.extensions import db
-from app.models import CustomDomain, GenEmail
+from app.models import CustomDomain, Alias
 
 
 @dashboard_bp.route("/domains/<int:custom_domain_id>/dns", methods=["GET", "POST"])
@@ -129,6 +129,6 @@ def domain_detail(custom_domain_id):
 
             return redirect(url_for("dashboard.custom_domain"))
 
-    nb_alias = GenEmail.filter_by(custom_domain_id=custom_domain.id).count()
+    nb_alias = Alias.filter_by(custom_domain_id=custom_domain.id).count()
 
     return render_template("dashboard/domain_detail/info.html", **locals())

+ 52 - 61
app/dashboard/views/index.py

@@ -10,7 +10,7 @@ from app.dashboard.base import dashboard_bp
 from app.extensions import db
 from app.log import LOG
 from app.models import (
-    GenEmail,
+    Alias,
     ClientUser,
     Contact,
     EmailLog,
@@ -22,7 +22,7 @@ from app.models import (
 
 class AliasInfo:
     id: int
-    gen_email: GenEmail
+    alias: Alias
     mailbox: Mailbox
     nb_forward: int
     nb_blocked: int
@@ -41,21 +41,21 @@ class AliasInfo:
 @login_required
 def index():
     query = request.args.get("query") or ""
-    highlight_gen_email_id = None
-    if request.args.get("highlight_gen_email_id"):
-        highlight_gen_email_id = int(request.args.get("highlight_gen_email_id"))
+    highlight_alias_id = None
+    if request.args.get("highlight_alias_id"):
+        highlight_alias_id = int(request.args.get("highlight_alias_id"))
 
     # User generates a new email
     if request.method == "POST":
         if request.form.get("form-name") == "trigger-email":
-            gen_email_id = request.form.get("gen-email-id")
-            gen_email = GenEmail.get(gen_email_id)
+            alias_id = request.form.get("alias-id")
+            alias = Alias.get(alias_id)
 
-            LOG.d("trigger an email to %s", gen_email)
-            email_utils.send_test_email_alias(gen_email.email, gen_email.user.name)
+            LOG.d("trigger an email to %s", alias)
+            email_utils.send_test_email_alias(alias.email, alias.user.name)
 
             flash(
-                f"An email sent to {gen_email.email} is on its way, please check your inbox/spam folder",
+                f"An email sent to {alias.email} is on its way, please check your inbox/spam folder",
                 "success",
             )
 
@@ -72,51 +72,47 @@ def index():
                 )
                 if not scheme or not AliasGeneratorEnum.has_value(scheme):
                     scheme = current_user.alias_generator
-                gen_email = GenEmail.create_new_random(user=current_user, scheme=scheme)
+                alias = Alias.create_new_random(user=current_user, scheme=scheme)
 
-                gen_email.mailbox_id = current_user.default_mailbox_id
+                alias.mailbox_id = current_user.default_mailbox_id
 
                 db.session.commit()
 
-                LOG.d("generate new email %s for user %s", gen_email, current_user)
-                flash(f"Alias {gen_email.email} has been created", "success")
+                LOG.d("generate new email %s for user %s", alias, current_user)
+                flash(f"Alias {alias.email} has been created", "success")
 
                 return redirect(
                     url_for(
-                        "dashboard.index",
-                        highlight_gen_email_id=gen_email.id,
-                        query=query,
+                        "dashboard.index", highlight_alias_id=alias.id, query=query,
                     )
                 )
             else:
                 flash(f"You need to upgrade your plan to create new alias.", "warning")
 
         elif request.form.get("form-name") == "switch-email-forwarding":
-            gen_email_id = request.form.get("gen-email-id")
-            gen_email: GenEmail = GenEmail.get(gen_email_id)
+            alias_id = request.form.get("alias-id")
+            alias: Alias = Alias.get(alias_id)
 
-            LOG.d("switch email forwarding for %s", gen_email)
+            LOG.d("switch email forwarding for %s", alias)
 
-            gen_email.enabled = not gen_email.enabled
-            if gen_email.enabled:
-                flash(f"Alias {gen_email.email} is enabled", "success")
+            alias.enabled = not alias.enabled
+            if alias.enabled:
+                flash(f"Alias {alias.email} is enabled", "success")
             else:
-                flash(f"Alias {gen_email.email} is disabled", "warning")
+                flash(f"Alias {alias.email} is disabled", "warning")
 
             db.session.commit()
             return redirect(
-                url_for(
-                    "dashboard.index", highlight_gen_email_id=gen_email.id, query=query
-                )
+                url_for("dashboard.index", highlight_alias_id=alias.id, query=query)
             )
 
         elif request.form.get("form-name") == "delete-email":
-            gen_email_id = request.form.get("gen-email-id")
-            gen_email: GenEmail = GenEmail.get(gen_email_id)
+            alias_id = request.form.get("alias-id")
+            alias: Alias = Alias.get(alias_id)
 
-            LOG.d("delete gen email %s", gen_email)
-            email = gen_email.email
-            GenEmail.delete(gen_email.id)
+            LOG.d("delete gen email %s", alias)
+            email = alias.email
+            Alias.delete(alias.id)
             db.session.commit()
             flash(f"Alias {email} has been deleted", "success")
 
@@ -130,42 +126,37 @@ def index():
                 db.session.rollback()
 
         elif request.form.get("form-name") == "set-note":
-            gen_email_id = request.form.get("gen-email-id")
-            gen_email: GenEmail = GenEmail.get(gen_email_id)
+            alias_id = request.form.get("alias-id")
+            alias: Alias = Alias.get(alias_id)
             note = request.form.get("note")
 
-            gen_email.note = note
+            alias.note = note
             db.session.commit()
 
-            flash(f"Update note for alias {gen_email.email}", "success")
+            flash(f"Update note for alias {alias.email}", "success")
             return redirect(
-                url_for(
-                    "dashboard.index", highlight_gen_email_id=gen_email.id, query=query
-                )
+                url_for("dashboard.index", highlight_alias_id=alias.id, query=query)
             )
 
         elif request.form.get("form-name") == "set-mailbox":
-            gen_email_id = request.form.get("gen-email-id")
-            gen_email: GenEmail = GenEmail.get(gen_email_id)
+            alias_id = request.form.get("alias-id")
+            alias: Alias = Alias.get(alias_id)
             mailbox_email = request.form.get("mailbox")
 
             mailbox = Mailbox.get_by(email=mailbox_email)
             if not mailbox or mailbox.user_id != current_user.id:
                 flash("Something went wrong, please retry", "warning")
             else:
-                gen_email.mailbox_id = mailbox.id
+                alias.mailbox_id = mailbox.id
                 db.session.commit()
-                LOG.d("Set alias %s mailbox to %s", gen_email, mailbox)
+                LOG.d("Set alias %s mailbox to %s", alias, mailbox)
 
                 flash(
-                    f"Update mailbox for {gen_email.email} to {mailbox_email}",
-                    "success",
+                    f"Update mailbox for {alias.email} to {mailbox_email}", "success",
                 )
                 return redirect(
                     url_for(
-                        "dashboard.index",
-                        highlight_gen_email_id=gen_email.id,
-                        query=query,
+                        "dashboard.index", highlight_alias_id=alias.id, query=query,
                     )
                 )
 
@@ -174,7 +165,7 @@ def index():
     client_users = (
         ClientUser.filter_by(user_id=current_user.id)
         .options(joinedload(ClientUser.client))
-        .options(joinedload(ClientUser.gen_email))
+        .options(joinedload(ClientUser.alias))
         .all()
     )
 
@@ -185,8 +176,8 @@ def index():
     return render_template(
         "dashboard/index.html",
         client_users=client_users,
-        aliases=get_alias_info(current_user, query, highlight_gen_email_id),
-        highlight_gen_email_id=highlight_gen_email_id,
+        aliases=get_alias_info(current_user, query, highlight_alias_id),
+        highlight_alias_id=highlight_alias_id,
         query=query,
         AliasGeneratorEnum=AliasGeneratorEnum,
         mailboxes=mailboxes,
@@ -194,7 +185,7 @@ def index():
 
 
 def get_alias_info(
-    user, query=None, highlight_gen_email_id=None, page_id=None
+    user, query=None, highlight_alias_id=None, page_id=None
 ) -> [AliasInfo]:
     if query:
         query = query.strip().lower()
@@ -202,17 +193,17 @@ def get_alias_info(
     aliases = {}  # dict of alias and AliasInfo
 
     q = (
-        db.session.query(GenEmail, Contact, EmailLog, Mailbox)
-        .join(Contact, GenEmail.id == Contact.gen_email_id, isouter=True)
+        db.session.query(Alias, Contact, EmailLog, Mailbox)
+        .join(Contact, Alias.id == Contact.gen_email_id, isouter=True)
         .join(EmailLog, Contact.id == EmailLog.contact_id, isouter=True)
-        .join(Mailbox, GenEmail.mailbox_id == Mailbox.id, isouter=True)
-        .filter(GenEmail.user_id == user.id)
-        .order_by(GenEmail.created_at.desc())
+        .join(Mailbox, Alias.mailbox_id == Mailbox.id, isouter=True)
+        .filter(Alias.user_id == user.id)
+        .order_by(Alias.created_at.desc())
     )
 
     if query:
         q = q.filter(
-            or_(GenEmail.email.ilike(f"%{query}%"), GenEmail.note.ilike(f"%{query}%"))
+            or_(Alias.email.ilike(f"%{query}%"), Alias.note.ilike(f"%{query}%"))
         )
 
     # pagination activated
@@ -223,11 +214,11 @@ def get_alias_info(
         if ge.email not in aliases:
             aliases[ge.email] = AliasInfo(
                 id=ge.id,
-                gen_email=ge,
+                alias=ge,
                 nb_blocked=0,
                 nb_forward=0,
                 nb_reply=0,
-                highlight=ge.id == highlight_gen_email_id,
+                highlight=ge.id == highlight_alias_id,
                 mailbox=mb,
                 note=ge.note,
             )
@@ -257,7 +248,7 @@ def get_alias_info(
 
     # only show intro on the first enabled alias
     for alias in ret:
-        if alias.gen_email.enabled:
+        if alias.alias.enabled:
             alias.show_intro_test_send_email = True
             break
 

+ 2 - 2
app/dashboard/views/mailbox_detail.py

@@ -12,7 +12,7 @@ from app.email_utils import can_be_used_as_personal_email, email_already_used
 from app.email_utils import mailbox_already_used, render, send_email
 from app.extensions import db
 from app.log import LOG
-from app.models import GenEmail, DeletedAlias
+from app.models import Alias, DeletedAlias
 from app.models import Mailbox
 from app.pgp_utils import PGPException, load_public_key
 from smtplib import SMTPRecipientsRefused
@@ -49,7 +49,7 @@ def mailbox_detail_route(mailbox_id):
                 # check if this email is not already used
                 if (
                     mailbox_already_used(new_email, current_user)
-                    or GenEmail.get_by(email=new_email)
+                    or Alias.get_by(email=new_email)
                     or DeletedAlias.get_by(email=new_email)
                 ):
                     flash(f"Email {new_email} already used", "error")

+ 3 - 5
app/dashboard/views/setting.py

@@ -21,7 +21,7 @@ from app.models import (
     ResetPasswordCode,
     EmailChange,
     User,
-    GenEmail,
+    Alias,
     DeletedAlias,
     CustomDomain,
     Client,
@@ -71,7 +71,7 @@ def setting():
                     # check if this email is not already used
                     if (
                         email_already_used(new_email)
-                        or GenEmail.get_by(email=new_email)
+                        or Alias.get_by(email=new_email)
                         or DeletedAlias.get_by(email=new_email)
                     ):
                         flash(f"Email {new_email} already used", "error")
@@ -165,9 +165,7 @@ def setting():
                 "custom_domains": [],
             }
 
-            for alias in GenEmail.filter_by(
-                user_id=current_user.id
-            ).all():  # type: GenEmail
+            for alias in Alias.filter_by(user_id=current_user.id).all():  # type: Alias
                 data["aliases"].append(dict(email=alias.email, enabled=alias.enabled))
 
             for custom_domain in CustomDomain.filter_by(user_id=current_user.id).all():

+ 10 - 10
app/dashboard/views/unsubscribe.py

@@ -7,18 +7,18 @@ from flask_login import login_required, current_user
 
 from app.dashboard.base import dashboard_bp
 from app.extensions import db
-from app.models import GenEmail
+from app.models import Alias
 
 
-@dashboard_bp.route("/unsubscribe/<gen_email_id>", methods=["GET", "POST"])
+@dashboard_bp.route("/unsubscribe/<alias_id>", methods=["GET", "POST"])
 @login_required
-def unsubscribe(gen_email_id):
-    gen_email = GenEmail.get(gen_email_id)
-    if not gen_email:
+def unsubscribe(alias_id):
+    alias = Alias.get(alias_id)
+    if not alias:
         flash("Incorrect link. Redirect you to the home page", "warning")
         return redirect(url_for("dashboard.index"))
 
-    if gen_email.user_id != current_user.id:
+    if alias.user_id != current_user.id:
         flash(
             "You don't have access to this page. Redirect you to the home page",
             "warning",
@@ -27,10 +27,10 @@ def unsubscribe(gen_email_id):
 
     # automatic unsubscribe, according to https://tools.ietf.org/html/rfc8058
     if request.method == "POST":
-        gen_email.enabled = False
-        flash(f"Alias {gen_email.email} has been blocked", "success")
+        alias.enabled = False
+        flash(f"Alias {alias.email} has been blocked", "success")
         db.session.commit()
 
-        return redirect(url_for("dashboard.index", highlight_gen_email_id=gen_email.id))
+        return redirect(url_for("dashboard.index", highlight_alias_id=alias.id))
     else:  # ask user confirmation
-        return render_template("dashboard/unsubscribe.html", alias=gen_email.email)
+        return render_template("dashboard/unsubscribe.html", alias=alias.email)

+ 6 - 6
app/email_utils.py

@@ -231,20 +231,20 @@ def send_email(
     smtp.sendmail(SUPPORT_EMAIL, to_email, msg_raw)
 
 
-def get_email_local_part(email):
+def get_email_local_part(address):
     """
     Get the local part from email
     ab@cd.com -> ab
     """
-    return email[: email.find("@")]
+    return address[: address.find("@")]
 
 
-def get_email_domain_part(email):
+def get_email_domain_part(address):
     """
     Get the domain part from email
     ab@cd.com -> cd.com
     """
-    return email[email.find("@") + 1 :]
+    return address[address.find("@") + 1 :]
 
 
 def add_dkim_signature(msg: Message, email_domain: str):
@@ -292,10 +292,10 @@ def delete_all_headers_except(msg: Message, headers: [str]):
             del msg._headers[i]
 
 
-def email_belongs_to_alias_domains(email: str) -> bool:
+def email_belongs_to_alias_domains(address: str) -> bool:
     """return True if an email ends with one of the alias domains provided by SimpleLogin"""
     for domain in ALIAS_DOMAINS:
-        if email.endswith("@" + domain):
+        if address.endswith("@" + domain):
             return True
 
     return False

+ 23 - 25
app/models.py

@@ -164,7 +164,7 @@ class User(db.Model, ModelMixin, UserMixin):
         user.default_mailbox_id = mb.id
 
         # create a first alias mail to show user how to use when they login
-        GenEmail.create_new(user, prefix="my-first-alias", mailbox_id=mb.id)
+        Alias.create_new(user, prefix="my-first-alias", mailbox_id=mb.id)
         db.session.flush()
 
         # Schedule onboarding emails
@@ -251,7 +251,7 @@ class User(db.Model, ModelMixin, UserMixin):
         if self.is_premium():
             return True
 
-        return GenEmail.filter_by(user_id=self.id).count() < MAX_NB_EMAIL_FREE_PLAN
+        return Alias.filter_by(user_id=self.id).count() < MAX_NB_EMAIL_FREE_PLAN
 
     def set_password(self, password):
         salt = bcrypt.gensalt()
@@ -275,16 +275,16 @@ class User(db.Model, ModelMixin, UserMixin):
         """return suggested email and other email choices """
         website_name = convert_to_id(website_name)
 
-        all_gen_emails = [ge.email for ge in GenEmail.filter_by(user_id=self.id)]
+        all_aliases = [ge.email for ge in Alias.filter_by(user_id=self.id)]
         if self.can_create_new_alias():
-            suggested_gen_email = GenEmail.create_new(self, prefix=website_name).email
+            suggested_alias = Alias.create_new(self, prefix=website_name).email
         else:
             # pick an email from the list of gen emails
-            suggested_gen_email = random.choice(all_gen_emails)
+            suggested_alias = random.choice(all_aliases)
 
         return (
-            suggested_gen_email,
-            list(set(all_gen_emails).difference({suggested_gen_email})),
+            suggested_alias,
+            list(set(all_aliases).difference({suggested_alias})),
         )
 
     def suggested_names(self) -> (str, [str]):
@@ -520,7 +520,7 @@ def generate_email(
         random_email = random_words() + "@" + EMAIL_DOMAIN
 
     # check that the client does not exist yet
-    if not GenEmail.get_by(email=random_email) and not DeletedAlias.get_by(
+    if not Alias.get_by(email=random_email) and not DeletedAlias.get_by(
         email=random_email
     ):
         LOG.debug("generate email %s", random_email)
@@ -531,8 +531,8 @@ def generate_email(
     return generate_email(scheme=scheme, in_hex=in_hex)
 
 
-class GenEmail(db.Model, ModelMixin):
-    """Generated email"""
+class Alias(db.Model, ModelMixin):
+    """Alias"""
 
     user_id = db.Column(db.ForeignKey(User.id, ondelete="cascade"), nullable=False)
     email = db.Column(db.String(128), unique=True, nullable=False)
@@ -576,7 +576,7 @@ class GenEmail(db.Model, ModelMixin):
             if not cls.get_by(email=email):
                 break
 
-        return GenEmail.create(
+        return Alias.create(
             user_id=user.id,
             email=email,
             note=note,
@@ -593,7 +593,7 @@ class GenEmail(db.Model, ModelMixin):
     ):
         """create a new random alias"""
         random_email = generate_email(scheme=scheme, in_hex=in_hex)
-        return GenEmail.create(
+        return Alias.create(
             user_id=user.id,
             email=random_email,
             mailbox_id=user.default_mailbox_id,
@@ -607,7 +607,7 @@ class GenEmail(db.Model, ModelMixin):
             return self.user.email
 
     def __repr__(self):
-        return f"<GenEmail {self.id} {self.email}>"
+        return f"<Alias {self.id} {self.email}>"
 
 
 class ClientUser(db.Model, ModelMixin):
@@ -619,9 +619,7 @@ class ClientUser(db.Model, ModelMixin):
     client_id = db.Column(db.ForeignKey(Client.id, ondelete="cascade"), nullable=False)
 
     # Null means client has access to user original email
-    gen_email_id = db.Column(
-        db.ForeignKey(GenEmail.id, ondelete="cascade"), nullable=True
-    )
+    gen_email_id = db.Column(db.ForeignKey(Alias.id, ondelete="cascade"), nullable=True)
 
     # user can decide to send to client another name
     name = db.Column(
@@ -633,13 +631,13 @@ class ClientUser(db.Model, ModelMixin):
         db.Boolean, nullable=False, default=False, server_default="0"
     )
 
-    gen_email = db.relationship(GenEmail, backref="client_users")
+    alias = db.relationship(Alias, backref="client_users")
 
     user = db.relationship(User)
     client = db.relationship(Client)
 
     def get_email(self):
-        return self.gen_email.email if self.gen_email_id else self.user.email
+        return self.alias.email if self.gen_email_id else self.user.email
 
     def get_user_name(self):
         if self.name:
@@ -690,7 +688,7 @@ class ClientUser(db.Model, ModelMixin):
                     LOG.debug(
                         "Use gen email for user %s, client %s", self.user, self.client
                     )
-                    res[Scope.EMAIL.value] = self.gen_email.email
+                    res[Scope.EMAIL.value] = self.alias.email
                 # Use user original email
                 else:
                     res[Scope.EMAIL.value] = self.user.email
@@ -708,7 +706,7 @@ class Contact(db.Model, ModelMixin):
     )
 
     gen_email_id = db.Column(
-        db.ForeignKey(GenEmail.id, ondelete="cascade"), nullable=False
+        db.ForeignKey(Alias.id, ondelete="cascade"), nullable=False
     )
 
     # used to be envelope header, should be mail header from instead
@@ -724,7 +722,7 @@ class Contact(db.Model, ModelMixin):
     # it has the prefix "reply+" to distinguish with other email
     reply_email = db.Column(db.String(512), nullable=False)
 
-    gen_email = db.relationship(GenEmail, backref="contacts")
+    alias = db.relationship(Alias, backref="contacts")
 
     def website_send_to(self):
         """return the email address with name.
@@ -854,7 +852,7 @@ class AliasUsedOn(db.Model, ModelMixin):
     )
 
     gen_email_id = db.Column(
-        db.ForeignKey(GenEmail.id, ondelete="cascade"), nullable=False
+        db.ForeignKey(Alias.id, ondelete="cascade"), nullable=False
     )
 
     hostname = db.Column(db.String(1024), nullable=False)
@@ -904,7 +902,7 @@ class CustomDomain(db.Model, ModelMixin):
     user = db.relationship(User)
 
     def nb_alias(self):
-        return GenEmail.filter_by(custom_domain_id=self.id).count()
+        return Alias.filter_by(custom_domain_id=self.id).count()
 
     def __repr__(self):
         return f"<Custom Domain {self.domain}>"
@@ -922,7 +920,7 @@ class Directory(db.Model, ModelMixin):
     user = db.relationship(User)
 
     def nb_alias(self):
-        return GenEmail.filter_by(directory_id=self.id).count()
+        return Alias.filter_by(directory_id=self.id).count()
 
     def __repr__(self):
         return f"<Directory {self.name}>"
@@ -954,7 +952,7 @@ class Mailbox(db.Model, ModelMixin):
     pgp_finger_print = db.Column(db.String(512), nullable=True)
 
     def nb_alias(self):
-        return GenEmail.filter_by(mailbox_id=self.id).count()
+        return Alias.filter_by(mailbox_id=self.id).count()
 
     def __repr__(self):
         return f"<Mailbox {self.email}>"

+ 10 - 10
app/oauth/views/authorize.py

@@ -13,7 +13,7 @@ from app.models import (
     Client,
     AuthorizationCode,
     ClientUser,
-    GenEmail,
+    Alias,
     RedirectUri,
     OauthToken,
     DeletedAlias,
@@ -157,7 +157,7 @@ def authorize():
             alias_prefix = request.form.get("prefix")
             alias_suffix = request.form.get("suffix")
 
-            gen_email = None
+            alias = None
 
             # user creates a new alias, not using suggested alias
             if alias_prefix:
@@ -176,14 +176,14 @@ def authorize():
                 ):
                     full_alias = alias_prefix + alias_suffix
 
-                    if GenEmail.get_by(email=full_alias) or DeletedAlias.get_by(
+                    if Alias.get_by(email=full_alias) or DeletedAlias.get_by(
                         email=full_alias
                     ):
                         LOG.error("alias %s already used, very rare!", full_alias)
                         flash(f"Alias {full_alias} already used", "error")
                         return redirect(request.url)
                     else:
-                        gen_email = GenEmail.create(
+                        alias = Alias.create(
                             user_id=current_user.id,
                             email=full_alias,
                             mailbox_id=current_user.default_mailbox_id,
@@ -193,7 +193,7 @@ def authorize():
                         alias_domain = get_email_domain_part(full_alias)
                         custom_domain = CustomDomain.get_by(domain=alias_domain)
                         if custom_domain:
-                            gen_email.custom_domain_id = custom_domain.id
+                            alias.custom_domain_id = custom_domain.id
 
                         db.session.flush()
                         flash(f"Alias {full_alias} has been created", "success")
@@ -206,9 +206,9 @@ def authorize():
                 chosen_email = request.form.get("suggested-email")
                 # todo: add some checks on chosen_email
                 if chosen_email != current_user.email:
-                    gen_email = GenEmail.get_by(email=chosen_email)
-                    if not gen_email:
-                        gen_email = GenEmail.create(
+                    alias = Alias.get_by(email=chosen_email)
+                    if not alias:
+                        alias = Alias.create(
                             email=chosen_email,
                             user_id=current_user.id,
                             mailbox_id=current_user.default_mailbox_id,
@@ -223,8 +223,8 @@ def authorize():
             client_user = ClientUser.create(
                 client_id=client.id, user_id=current_user.id
             )
-            if gen_email:
-                client_user.gen_email_id = gen_email.id
+            if alias:
+                client_user.gen_email_id = alias.id
 
             if custom_name:
                 client_user.name = custom_name

+ 12 - 12
cron.py

@@ -10,7 +10,7 @@ from app.log import LOG
 from app.models import (
     Subscription,
     User,
-    GenEmail,
+    Alias,
     EmailLog,
     Contact,
     CustomDomain,
@@ -111,18 +111,18 @@ def stats():
     LOG.d("total number user %s", nb_user)
 
     # nb gen emails
-    q = db.session.query(GenEmail, User).filter(GenEmail.user_id == User.id)
+    q = db.session.query(Alias, User).filter(Alias.user_id == User.id)
     for ie in IGNORED_EMAILS:
         q = q.filter(~User.email.contains(ie))
 
-    nb_gen_email = q.count()
-    LOG.d("total number alias %s", nb_gen_email)
+    nb_alias = q.count()
+    LOG.d("total number alias %s", nb_alias)
 
     # nb mails forwarded
-    q = db.session.query(EmailLog, Contact, GenEmail, User).filter(
+    q = db.session.query(EmailLog, Contact, Alias, User).filter(
         EmailLog.contact_id == Contact.id,
-        Contact.gen_email_id == GenEmail.id,
-        GenEmail.user_id == User.id,
+        Contact.gen_email_id == Alias.id,
+        Alias.user_id == User.id,
     )
     for ie in IGNORED_EMAILS:
         q = q.filter(~User.email.contains(ie))
@@ -141,11 +141,11 @@ def stats():
     nb_premium = Subscription.query.count()
     nb_custom_domain = CustomDomain.query.count()
 
-    nb_custom_domain_alias = GenEmail.query.filter(
-        GenEmail.custom_domain_id.isnot(None)
+    nb_custom_domain_alias = Alias.query.filter(
+        Alias.custom_domain_id.isnot(None)
     ).count()
 
-    nb_disabled_alias = GenEmail.query.filter(GenEmail.enabled == False).count()
+    nb_disabled_alias = Alias.query.filter(Alias.enabled == False).count()
 
     nb_app = Client.query.count()
 
@@ -153,7 +153,7 @@ def stats():
 
     send_email(
         ADMIN_EMAIL,
-        subject=f"SimpleLogin Stats for {today}, {nb_user} users, {nb_gen_email} aliases, {nb_forward} forwards",
+        subject=f"SimpleLogin Stats for {today}, {nb_user} users, {nb_alias} aliases, {nb_forward} forwards",
         plaintext="",
         html=f"""
 Stats for {today} <br>
@@ -161,7 +161,7 @@ Stats for {today} <br>
 nb_user: {nb_user} <br>
 nb_premium: {nb_premium} <br>
 
-nb_alias: {nb_gen_email} <br>
+nb_alias: {nb_alias} <br>
 nb_disabled_alias: {nb_disabled_alias} <br>
 
 nb_custom_domain: {nb_custom_domain} <br>

+ 2 - 2
docs/upgrade.md

@@ -25,7 +25,7 @@ docker exec -it sl-app python shell.py
 """
 from app.extensions import db
 from app.log import LOG
-from app.models import Mailbox, GenEmail, User
+from app.models import Mailbox, Alias, User
 
 for user in User.query.all():
     if user.default_mailbox_id:
@@ -40,7 +40,7 @@ for user in User.query.all():
         db.session.commit()
 
     # assign existing alias to this mailbox
-    for gen_email in GenEmail.query.filter_by(user_id=user.id):
+    for gen_email in Alias.query.filter_by(user_id=user.id):
         if not gen_email.mailbox_id:
             LOG.d("Set alias  %s mailbox to default mailbox", gen_email)
             gen_email.mailbox_id = default_mb.id

+ 64 - 66
email_handler.py

@@ -69,7 +69,7 @@ from app.email_utils import (
 from app.extensions import db
 from app.log import LOG
 from app.models import (
-    GenEmail,
+    Alias,
     Contact,
     EmailLog,
     CustomDomain,
@@ -98,35 +98,35 @@ def new_app():
     return app
 
 
-def try_auto_create(alias: str) -> Optional[GenEmail]:
+def try_auto_create(address: str) -> Optional[Alias]:
     """Try to auto-create the alias using directory or catch-all domain
     """
-    gen_email = try_auto_create_catch_all_domain(alias)
-    if not gen_email:
-        gen_email = try_auto_create_directory(alias)
+    alias = try_auto_create_catch_all_domain(address)
+    if not alias:
+        alias = try_auto_create_directory(address)
 
-    return gen_email
+    return alias
 
 
-def try_auto_create_directory(alias: str) -> Optional[GenEmail]:
+def try_auto_create_directory(address: str) -> Optional[Alias]:
     """
     Try to create an alias with directory
     """
     # check if alias belongs to a directory, ie having directory/anything@EMAIL_DOMAIN format
-    if email_belongs_to_alias_domains(alias):
+    if email_belongs_to_alias_domains(address):
         # if there's no directory separator in the alias, no way to auto-create it
-        if "/" not in alias and "+" not in alias and "#" not in alias:
+        if "/" not in address and "+" not in address and "#" not in address:
             return None
 
         # alias contains one of the 3 special directory separator: "/", "+" or "#"
-        if "/" in alias:
+        if "/" in address:
             sep = "/"
-        elif "+" in alias:
+        elif "+" in address:
             sep = "+"
         else:
             sep = "#"
 
-        directory_name = alias[: alias.find(sep)]
+        directory_name = address[: address.find(sep)]
         LOG.d("directory_name %s", directory_name)
 
         directory = Directory.get_by(name=directory_name)
@@ -136,37 +136,37 @@ def try_auto_create_directory(alias: str) -> Optional[GenEmail]:
         dir_user: User = directory.user
 
         if not dir_user.can_create_new_alias():
-            send_cannot_create_directory_alias(dir_user, alias, directory_name)
+            send_cannot_create_directory_alias(dir_user, address, directory_name)
             return None
 
         # if alias has been deleted before, do not auto-create it
-        if DeletedAlias.get_by(email=alias, user_id=directory.user_id):
+        if DeletedAlias.get_by(email=address, user_id=directory.user_id):
             LOG.warning(
                 "Alias %s was deleted before, cannot auto-create using directory %s, user %s",
-                alias,
+                address,
                 directory_name,
                 dir_user,
             )
             return None
 
-        LOG.d("create alias %s for directory %s", alias, directory)
+        LOG.d("create alias %s for directory %s", address, directory)
 
-        gen_email = GenEmail.create(
-            email=alias,
+        alias = Alias.create(
+            email=address,
             user_id=directory.user_id,
             directory_id=directory.id,
             mailbox_id=dir_user.default_mailbox_id,
         )
         db.session.commit()
-        return gen_email
+        return alias
 
 
-def try_auto_create_catch_all_domain(alias: str) -> Optional[GenEmail]:
+def try_auto_create_catch_all_domain(address: str) -> Optional[Alias]:
     """Try to create an alias with catch-all domain"""
 
     # try to create alias on-the-fly with custom-domain catch-all feature
     # check if alias is custom-domain alias and if the custom-domain has catch-all enabled
-    alias_domain = get_email_domain_part(alias)
+    alias_domain = get_email_domain_part(address)
     custom_domain = CustomDomain.get_by(domain=alias_domain)
 
     if not custom_domain:
@@ -180,23 +180,23 @@ def try_auto_create_catch_all_domain(alias: str) -> Optional[GenEmail]:
     domain_user: User = custom_domain.user
 
     if not domain_user.can_create_new_alias():
-        send_cannot_create_domain_alias(domain_user, alias, alias_domain)
+        send_cannot_create_domain_alias(domain_user, address, alias_domain)
         return None
 
     # if alias has been deleted before, do not auto-create it
-    if DeletedAlias.get_by(email=alias, user_id=custom_domain.user_id):
+    if DeletedAlias.get_by(email=address, user_id=custom_domain.user_id):
         LOG.warning(
             "Alias %s was deleted before, cannot auto-create using domain catch-all %s, user %s",
-            alias,
+            address,
             custom_domain,
             domain_user,
         )
         return None
 
-    LOG.d("create alias %s for domain %s", alias, custom_domain)
+    LOG.d("create alias %s for domain %s", address, custom_domain)
 
-    gen_email = GenEmail.create(
-        email=alias,
+    alias = Alias.create(
+        email=address,
         user_id=custom_domain.user_id,
         custom_domain_id=custom_domain.id,
         automatic_creation=True,
@@ -204,15 +204,15 @@ def try_auto_create_catch_all_domain(alias: str) -> Optional[GenEmail]:
     )
 
     db.session.commit()
-    return gen_email
+    return alias
 
 
-def get_or_create_contact(website_from_header: str, gen_email: GenEmail) -> Contact:
+def get_or_create_contact(website_from_header: str, alias: Alias) -> Contact:
     """
     website_from_header can be the full-form email, i.e. "First Last <email@example.com>"
     """
     _, website_email = parseaddr(website_from_header)
-    contact = Contact.get_by(gen_email_id=gen_email.id, website_email=website_email)
+    contact = Contact.get_by(gen_email_id=alias.id, website_email=website_email)
     if contact:
         # update the website_from if needed
         if contact.website_from != website_from_header:
@@ -222,7 +222,7 @@ def get_or_create_contact(website_from_header: str, gen_email: GenEmail) -> Cont
     else:
         LOG.debug(
             "create forward email for alias %s and website email %s",
-            gen_email,
+            alias,
             website_from_header,
         )
 
@@ -236,7 +236,7 @@ def get_or_create_contact(website_from_header: str, gen_email: GenEmail) -> Cont
             reply_email = f"reply+{random_string(30)}@{EMAIL_DOMAIN}"
 
         contact = Contact.create(
-            gen_email_id=gen_email.id,
+            gen_email_id=alias.id,
             website_email=website_email,
             website_from=website_from_header,
             reply_email=reply_email,
@@ -297,15 +297,15 @@ def handle_forward(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> str:
     """return *status_code message*"""
     alias = rcpt_to.lower()  # alias@SL
 
-    gen_email = GenEmail.get_by(email=alias)
-    if not gen_email:
+    alias = Alias.get_by(email=alias)
+    if not alias:
         LOG.d("alias %s not exist. Try to see if it can be created on the fly", alias)
-        gen_email = try_auto_create(alias)
-        if not gen_email:
+        alias = try_auto_create(alias)
+        if not alias:
             LOG.d("alias %s cannot be created on-the-fly, return 510", alias)
             return "510 Email not exist"
 
-    mailbox = gen_email.mailbox
+    mailbox = alias.mailbox
     mailbox_email = mailbox.email
 
     # create PGP email if needed
@@ -313,10 +313,10 @@ def handle_forward(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> str:
         LOG.d("Encrypt message using mailbox %s", mailbox)
         msg = prepare_pgp_message(msg, mailbox.pgp_finger_print)
 
-    contact = get_or_create_contact(msg["From"], gen_email)
+    contact = get_or_create_contact(msg["From"], alias)
     forward_log = EmailLog.create(contact_id=contact.id)
 
-    if gen_email.enabled:
+    if alias.enabled:
         # add custom header
         add_or_replace_header(msg, "X-SimpleLogin-Type", "Forward")
 
@@ -349,7 +349,7 @@ def handle_forward(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> str:
             add_or_replace_header(msg, "To", to_header)
 
         # add List-Unsubscribe header
-        unsubscribe_link = f"{URL}/dashboard/unsubscribe/{gen_email.id}"
+        unsubscribe_link = f"{URL}/dashboard/unsubscribe/{alias.id}"
         add_or_replace_header(msg, "List-Unsubscribe", f"<{unsubscribe_link}>")
         add_or_replace_header(
             msg, "List-Unsubscribe-Post", "List-Unsubscribe=One-Click"
@@ -376,7 +376,7 @@ def handle_forward(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> str:
             envelope.rcpt_options,
         )
     else:
-        LOG.d("%s is disabled, do not forward", gen_email)
+        LOG.d("%s is disabled, do not forward", alias)
         forward_log.blocked = True
 
     db.session.commit()
@@ -396,17 +396,17 @@ def handle_reply(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> str:
         LOG.warning(f"No such forward-email with {reply_email} as reply-email")
         return "550 wrong reply email"
 
-    alias: str = contact.gen_email.email
-    alias_domain = alias[alias.find("@") + 1 :]
+    address: str = contact.alias.email
+    alias_domain = address[address.find("@") + 1 :]
 
     # alias must end with one of the ALIAS_DOMAINS or custom-domain
-    if not email_belongs_to_alias_domains(alias):
+    if not email_belongs_to_alias_domains(address):
         if not CustomDomain.get_by(domain=alias_domain):
             return "550 alias unknown by SimpleLogin"
 
-    gen_email = contact.gen_email
-    user = gen_email.user
-    mailbox_email = gen_email.mailbox_email()
+    alias = contact.alias
+    user = alias.user
+    mailbox_email = alias.mailbox_email()
 
     # bounce email initiated by Postfix
     # can happen in case emails cannot be delivered to user-email
@@ -415,14 +415,12 @@ def handle_reply(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> str:
     if envelope.mail_from == "<>":
         LOG.error(
             "Bounce when sending to alias %s from %s, user %s",
-            alias,
+            address,
             contact.website_from,
-            gen_email.user,
+            alias.user,
         )
 
-        handle_bounce(
-            alias, envelope, contact, gen_email, msg, smtp, user, mailbox_email
-        )
+        handle_bounce(address, envelope, contact, alias, msg, smtp, user, mailbox_email)
         return "550 ignored"
 
     # only mailbox can send email to the reply-email
@@ -435,21 +433,21 @@ def handle_reply(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> str:
             reply_email,
         )
 
-        user = gen_email.user
+        user = alias.user
         send_email(
             mailbox_email,
-            f"Reply from your alias {alias} only works from your mailbox",
+            f"Reply from your alias {address} only works from your mailbox",
             render(
                 "transactional/reply-must-use-personal-email.txt",
                 name=user.name,
-                alias=alias,
+                alias=address,
                 sender=envelope.mail_from,
                 mailbox_email=mailbox_email,
             ),
             render(
                 "transactional/reply-must-use-personal-email.html",
                 name=user.name,
-                alias=alias,
+                alias=address,
                 sender=envelope.mail_from,
                 mailbox_email=mailbox_email,
             ),
@@ -472,7 +470,7 @@ def handle_reply(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> str:
     delete_header(msg, "DKIM-Signature")
 
     # the email comes from alias
-    add_or_replace_header(msg, "From", alias)
+    add_or_replace_header(msg, "From", address)
 
     # some email providers like ProtonMail adds automatically the Reply-To field
     # make sure to delete it
@@ -493,7 +491,7 @@ def handle_reply(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> str:
 
     LOG.d(
         "send email from %s to %s, mail_options:%s,rcpt_options:%s",
-        alias,
+        address,
         contact.website_email,
         envelope.mail_options,
         envelope.rcpt_options,
@@ -509,7 +507,7 @@ def handle_reply(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> str:
 
     msg_raw = msg.as_string().encode()
     smtp.sendmail(
-        alias,
+        address,
         contact.website_email,
         msg_raw,
         envelope.mail_options,
@@ -522,12 +520,12 @@ def handle_reply(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> str:
     return "250 Message accepted for delivery"
 
 
-def handle_bounce(alias, envelope, contact, gen_email, msg, smtp, user, mailbox_email):
+def handle_bounce(address, envelope, contact, alias, msg, smtp, user, mailbox_email):
     fel: EmailLog = EmailLog.create(contact_id=contact.id, bounced=True)
     db.session.commit()
 
     nb_bounced = EmailLog.filter_by(contact_id=contact.id, bounced=True).count()
-    disable_alias_link = f"{URL}/dashboard/unsubscribe/{gen_email.id}"
+    disable_alias_link = f"{URL}/dashboard/unsubscribe/{alias.id}"
 
     # Store the bounced email
     orig_msg = get_orig_message_from_bounce(msg)
@@ -560,12 +558,12 @@ def handle_bounce(alias, envelope, contact, gen_email, msg, smtp, user, mailbox_
             "Inform user %s about bounced email sent by %s to alias %s",
             user,
             contact.website_from,
-            alias,
+            address,
         )
         send_email(
             # use user mail here as only user is authenticated to see the refused email
             user.email,
-            f"Email from {contact.website_from} to {alias} cannot be delivered to your inbox",
+            f"Email from {contact.website_from} to {address} cannot be delivered to your inbox",
             render(
                 "transactional/bounced-email.txt",
                 name=user.name,
@@ -593,16 +591,16 @@ def handle_bounce(alias, envelope, contact, gen_email, msg, smtp, user, mailbox_
     elif nb_bounced >= 2:
         LOG.d(
             "Bounce happens again with alias %s from %s. Disable alias now ",
-            alias,
+            address,
             contact.website_from,
         )
-        gen_email.enabled = False
+        alias.enabled = False
         db.session.commit()
 
         send_email(
             # use user mail here as only user is authenticated to see the refused email
             user.email,
-            f"Alias {alias} has been disabled due to second undelivered email from {contact.website_from}",
+            f"Alias {address} has been disabled due to second undelivered email from {contact.website_from}",
             render(
                 "transactional/automatic-disable-alias.txt",
                 name=user.name,

+ 3 - 3
server.py

@@ -40,7 +40,7 @@ from app.models import (
     Client,
     User,
     ClientUser,
-    GenEmail,
+    Alias,
     RedirectUri,
     Subscription,
     PlanEnum,
@@ -161,7 +161,7 @@ def fake_data():
 
     user.default_mailbox_id = m1.id
 
-    GenEmail.create_new(user, "e1@", mailbox_id=m1.id)
+    Alias.create_new(user, "e1@", mailbox_id=m1.id)
 
     CustomDomain.create(user_id=user.id, domain="ab.cd", verified=True)
     CustomDomain.create(
@@ -428,7 +428,7 @@ def init_admin(app):
     admin.init_app(app, index_view=SLAdminIndexView())
     admin.add_view(SLModelView(User, db.session))
     admin.add_view(SLModelView(Client, db.session))
-    admin.add_view(SLModelView(GenEmail, db.session))
+    admin.add_view(SLModelView(Alias, db.session))
     admin.add_view(SLModelView(ClientUser, db.session))
 
 

+ 2 - 2
templates/emails/transactional/automatic-disable-alias.html

@@ -2,14 +2,14 @@
 
 {% block content %}
   {{ render_text("Hi " + name) }}
-  {{ render_text("There are at least 2 emails sent to your alias <b>" + alias + "</b> from <b>" + website_email + "</b> that have been <b>refused</b> (or bounced) by your mailbox " + mailbox_email + ".") }}
+  {{ render_text("There are at least 2 emails sent to your alias <b>" + alias.email + "</b> from <b>" + website_email + "</b> that have been <b>refused</b> (or bounced) by your mailbox " + mailbox_email + ".") }}
 
 
   {{ render_text("This is usually due to the email being considered as <b>spam</b> by your email provider.") }}
 
   {{ render_button("View the refused email", refused_email_url) }}
 
-  {{ render_text('As security measure, we have <b>disabled</b> the alias ' + alias + ".") }}
+  {{ render_text('As security measure, we have <b>disabled</b> the alias ' + alias.email + ".") }}
 
   {{ render_text('Please let us know if you have any question.') }}
 

+ 2 - 2
templates/emails/transactional/automatic-disable-alias.txt

@@ -1,13 +1,13 @@
 Hi {{name}}
 
-There are at least 2 emails sent to your alias {{alias}} from {{website_from}} that have been refused (or bounced) by your mailbox {{mailbox_email}}.
+There are at least 2 emails sent to your alias {{alias.email}} from {{website_from}} that have been refused (or bounced) by your mailbox {{mailbox_email}}.
 
 This is usually due to the email being considered as spam by your email provider.
 You can view this email here:
 {{ refused_email_url }}
 
 
-As security measure, we have disabled the alias {{alias}}.
+As security measure, we have disabled the alias {{alias.email}}.
 
 Please let us know if you have any question.
 

+ 2 - 2
templates/emails/transactional/bounced-email.html

@@ -2,7 +2,7 @@
 
 {% block content %}
   {{ render_text("Hi " + name) }}
-  {{ render_text("An email sent to your alias <b>" + alias + "</b> from <b>" + website_email + "</b> was <b>refused</b> (or bounced) by your mailbox " + mailbox_email + ".") }}
+  {{ render_text("An email sent to your alias <b>" + alias.email + "</b> from <b>" + website_email + "</b> was <b>refused</b> (or bounced) by your mailbox " + mailbox_email + ".") }}
 
   {{ render_text('This is usually due to the email being considered as <b>spam</b> by your email provider.') }}
 
@@ -12,7 +12,7 @@
 
   {{ render_text('1. If the email is not spam at all, it means your email provider has wrongly classified it as spam. In this case you can <b>create a filter to whitelist</b> it. The filter could be based on the sender, email subject, etc. As how to create the filter differs for each email provider, please check with your email provider on how to whitelist an email. Let us know if you need help to setup the filter by replying to this email.') }}
 
-  {{ render_text('2. If this email is indeed spam, it means your alias <b>' + alias + '</b> is now in the hands of a spammer. In this case, you should <b>disable</b> or delete the alias immediately. Or, do nothing and we\'ll <b>automatically</b> disable this alias the second time the email is refused. Don\'t worry, we\'ll send you another email when that happens.') }}
+  {{ render_text('2. If this email is indeed spam, it means your alias <b>' + alias.email + '</b> is now in the hands of a spammer. In this case, you should <b>disable</b> or delete the alias immediately. Or, do nothing and we\'ll <b>automatically</b> disable this alias the second time the email is refused. Don\'t worry, we\'ll send you another email when that happens.') }}
 
   {{ render_button("Disable alias", disable_alias_link) }}
 

+ 1 - 1
templates/emails/transactional/bounced-email.txt

@@ -1,6 +1,6 @@
 Hi {{name}}
 
-An email sent to your alias {{alias}} from {{website_from}} was refused (or bounced) by your mailbox {{mailbox_email}}.
+An email sent to your alias {{alias.email}} from {{website_from}} was refused (or bounced) by your mailbox {{mailbox_email}}.
 
 This is usually due to the email being considered as spam by your email provider.
 You can view this email here:

+ 19 - 19
tests/api/test_alias.py

@@ -4,7 +4,7 @@ from flask import url_for
 
 from app.config import EMAIL_DOMAIN, MAX_NB_EMAIL_FREE_PLAN, PAGE_LIMIT
 from app.extensions import db
-from app.models import User, ApiKey, GenEmail, Contact, EmailLog
+from app.models import User, ApiKey, Alias, Contact, EmailLog
 from app.utils import random_word
 
 
@@ -38,7 +38,7 @@ def test_success_with_pagination(flask_client):
 
     # create more aliases than PAGE_LIMIT
     for _ in range(PAGE_LIMIT + 1):
-        GenEmail.create_new_random(user)
+        Alias.create_new_random(user)
     db.session.commit()
 
     # get aliases on the 1st page, should return PAGE_LIMIT aliases
@@ -80,11 +80,11 @@ def test_delete_alias(flask_client):
     api_key = ApiKey.create(user.id, "for test")
     db.session.commit()
 
-    gen_email = GenEmail.create_new_random(user)
+    alias = Alias.create_new_random(user)
     db.session.commit()
 
     r = flask_client.delete(
-        url_for("api.delete_alias", alias_id=gen_email.id),
+        url_for("api.delete_alias", alias_id=alias.id),
         headers={"Authentication": api_key.code},
     )
 
@@ -102,11 +102,11 @@ def test_toggle_alias(flask_client):
     api_key = ApiKey.create(user.id, "for test")
     db.session.commit()
 
-    gen_email = GenEmail.create_new_random(user)
+    alias = Alias.create_new_random(user)
     db.session.commit()
 
     r = flask_client.post(
-        url_for("api.toggle_alias", alias_id=gen_email.id),
+        url_for("api.toggle_alias", alias_id=alias.id),
         headers={"Authentication": api_key.code},
     )
 
@@ -124,14 +124,14 @@ def test_alias_activities(flask_client):
     api_key = ApiKey.create(user.id, "for test")
     db.session.commit()
 
-    gen_email = GenEmail.create_new_random(user)
+    alias = Alias.create_new_random(user)
     db.session.commit()
 
     # create some alias log
     contact = Contact.create(
         website_email="marketing@example.com",
         reply_email="reply@a.b",
-        gen_email_id=gen_email.id,
+        gen_email_id=alias.id,
     )
     db.session.commit()
 
@@ -142,7 +142,7 @@ def test_alias_activities(flask_client):
         EmailLog.create(contact_id=contact.id, blocked=True)
 
     r = flask_client.get(
-        url_for("api.get_alias_activities", alias_id=gen_email.id, page_id=0),
+        url_for("api.get_alias_activities", alias_id=alias.id, page_id=0),
         headers={"Authentication": api_key.code},
     )
 
@@ -156,7 +156,7 @@ def test_alias_activities(flask_client):
 
     # second page, should return 1 or 2 results only
     r = flask_client.get(
-        url_for("api.get_alias_activities", alias_id=gen_email.id, page_id=1),
+        url_for("api.get_alias_activities", alias_id=alias.id, page_id=1),
         headers={"Authentication": api_key.code},
     )
     assert len(r.json["activities"]) < 3
@@ -172,11 +172,11 @@ def test_update_alias(flask_client):
     api_key = ApiKey.create(user.id, "for test")
     db.session.commit()
 
-    gen_email = GenEmail.create_new_random(user)
+    alias = Alias.create_new_random(user)
     db.session.commit()
 
     r = flask_client.put(
-        url_for("api.update_alias", alias_id=gen_email.id),
+        url_for("api.update_alias", alias_id=alias.id),
         headers={"Authentication": api_key.code},
         json={"note": "test note"},
     )
@@ -195,7 +195,7 @@ def test_alias_contacts(flask_client):
     api_key = ApiKey.create(user.id, "for test")
     db.session.commit()
 
-    gen_email = GenEmail.create_new_random(user)
+    alias = Alias.create_new_random(user)
     db.session.commit()
 
     # create some alias log
@@ -203,7 +203,7 @@ def test_alias_contacts(flask_client):
         contact = Contact.create(
             website_email=f"marketing-{i}@example.com",
             reply_email=f"reply-{i}@a.b",
-            gen_email_id=gen_email.id,
+            gen_email_id=alias.id,
         )
         db.session.commit()
 
@@ -211,7 +211,7 @@ def test_alias_contacts(flask_client):
         db.session.commit()
 
     r = flask_client.get(
-        url_for("api.get_alias_contacts_route", alias_id=gen_email.id, page_id=0),
+        url_for("api.get_alias_contacts_route", alias_id=alias.id, page_id=0),
         headers={"Authentication": api_key.code},
     )
 
@@ -227,7 +227,7 @@ def test_alias_contacts(flask_client):
 
     # second page, should return 1 result only
     r = flask_client.get(
-        url_for("api.get_alias_contacts_route", alias_id=gen_email.id, page_id=1),
+        url_for("api.get_alias_contacts_route", alias_id=alias.id, page_id=1),
         headers={"Authentication": api_key.code},
     )
     assert len(r.json["contacts"]) == 1
@@ -243,11 +243,11 @@ def test_create_contact_route(flask_client):
     api_key = ApiKey.create(user.id, "for test")
     db.session.commit()
 
-    gen_email = GenEmail.create_new_random(user)
+    alias = Alias.create_new_random(user)
     db.session.commit()
 
     r = flask_client.post(
-        url_for("api.create_contact_route", alias_id=gen_email.id),
+        url_for("api.create_contact_route", alias_id=alias.id),
         headers={"Authentication": api_key.code},
         json={"contact": "First Last <first@example.com>"},
     )
@@ -262,7 +262,7 @@ def test_create_contact_route(flask_client):
 
     # re-add a contact, should return 409
     r = flask_client.post(
-        url_for("api.create_contact_route", alias_id=gen_email.id),
+        url_for("api.create_contact_route", alias_id=alias.id),
         headers={"Authentication": api_key.code},
         json={"contact": "First2 Last2 <first@example.com>"},
     )

+ 3 - 3
tests/api/test_alias_options.py

@@ -1,7 +1,7 @@
 from flask import url_for
 
 from app.extensions import db
-from app.models import User, ApiKey, AliasUsedOn, GenEmail
+from app.models import User, ApiKey, AliasUsedOn, Alias
 
 
 def test_different_scenarios(flask_client):
@@ -40,7 +40,7 @@ def test_different_scenarios(flask_client):
     assert r.json["custom"]["suggestion"] == "test"
 
     # <<< with recommendation >>>
-    alias = GenEmail.create_new(user, prefix="test")
+    alias = Alias.create_new(user, prefix="test")
     db.session.commit()
     AliasUsedOn.create(gen_email_id=alias.id, hostname="www.test.com")
     db.session.commit()
@@ -85,7 +85,7 @@ def test_different_scenarios_v2(flask_client):
     assert r.json["prefix_suggestion"] == "test"
 
     # <<< with recommendation >>>
-    alias = GenEmail.create_new(user, prefix="test")
+    alias = Alias.create_new(user, prefix="test")
     db.session.commit()
     AliasUsedOn.create(gen_email_id=alias.id, hostname="www.test.com")
     db.session.commit()

+ 4 - 4
tests/api/test_new_custom_alias.py

@@ -2,7 +2,7 @@ from flask import url_for
 
 from app.config import EMAIL_DOMAIN, MAX_NB_EMAIL_FREE_PLAN
 from app.extensions import db
-from app.models import User, ApiKey, GenEmail
+from app.models import User, ApiKey, Alias
 from app.utils import random_word
 
 
@@ -31,7 +31,7 @@ def test_success(flask_client):
     assert r.status_code == 201
     assert r.json["alias"] == f"prefix.{word}@{EMAIL_DOMAIN}"
 
-    new_ge = GenEmail.get_by(email=r.json["alias"])
+    new_ge = Alias.get_by(email=r.json["alias"])
     assert new_ge.note == "test note"
 
 
@@ -56,7 +56,7 @@ def test_create_custom_alias_without_note(flask_client):
     assert r.status_code == 201
     assert r.json["alias"] == f"prefix.{word}@{EMAIL_DOMAIN}"
 
-    new_ge = GenEmail.get_by(email=r.json["alias"])
+    new_ge = Alias.get_by(email=r.json["alias"])
     assert new_ge.note is None
 
 
@@ -73,7 +73,7 @@ def test_out_of_quota(flask_client):
 
     # create MAX_NB_EMAIL_FREE_PLAN custom alias to run out of quota
     for _ in range(MAX_NB_EMAIL_FREE_PLAN):
-        GenEmail.create_new(user, prefix="test")
+        Alias.create_new(user, prefix="test")
 
     word = random_word()
     r = flask_client.post(

+ 3 - 3
tests/api/test_new_random_alias.py

@@ -4,7 +4,7 @@ from flask import url_for
 
 from app.config import EMAIL_DOMAIN, MAX_NB_EMAIL_FREE_PLAN
 from app.extensions import db
-from app.models import User, ApiKey, GenEmail
+from app.models import User, ApiKey, Alias
 
 
 def test_success(flask_client):
@@ -57,7 +57,7 @@ def test_custom_mode(flask_client):
 
     assert r.status_code == 201
     alias = r.json["alias"]
-    ge = GenEmail.get_by(email=alias)
+    ge = Alias.get_by(email=alias)
     assert ge.note == "test note"
 
 
@@ -74,7 +74,7 @@ def test_out_of_quota(flask_client):
 
     # create MAX_NB_EMAIL_FREE_PLAN random alias to run out of quota
     for _ in range(MAX_NB_EMAIL_FREE_PLAN):
-        GenEmail.create_new(user, prefix="test1")
+        Alias.create_new(user, prefix="test1")
 
     r = flask_client.post(
         url_for("api.new_random_alias", hostname="www.test.com"),

+ 1 - 1
tests/api/test_user_info.py

@@ -1,7 +1,7 @@
 from flask import url_for
 
 from app.extensions import db
-from app.models import User, ApiKey, AliasUsedOn, GenEmail
+from app.models import User, ApiKey, AliasUsedOn, Alias
 
 
 def test_user_in_trial(flask_client):

+ 7 - 7
tests/test_models.py

@@ -5,7 +5,7 @@ import pytest
 
 from app.config import EMAIL_DOMAIN, MAX_NB_EMAIL_FREE_PLAN
 from app.extensions import db
-from app.models import generate_email, User, GenEmail
+from app.models import generate_email, User, Alias
 
 
 def test_generate_email(flask_client):
@@ -42,24 +42,24 @@ def test_suggested_emails_for_user_who_cannot_create_new_alias(flask_client):
 
     # make sure user runs out of quota to create new email
     for i in range(MAX_NB_EMAIL_FREE_PLAN):
-        GenEmail.create_new(user=user, prefix="test")
+        Alias.create_new(user=user, prefix="test")
     db.session.commit()
 
     suggested_email, other_emails = user.suggested_emails(website_name="test")
 
-    # the suggested email is chosen from existing GenEmail
-    assert GenEmail.get_by(email=suggested_email)
+    # the suggested email is chosen from existing Alias
+    assert Alias.get_by(email=suggested_email)
 
     # all other emails are generated emails
     for email in other_emails:
-        assert GenEmail.get_by(email=email)
+        assert Alias.get_by(email=email)
 
 
-def test_gen_email_create_random(flask_client):
+def test_alias_create_random(flask_client):
     user = User.create(
         email="a@b.c", password="password", name="Test User", activated=True
     )
     db.session.commit()
 
-    alias = GenEmail.create_new_random(user)
+    alias = Alias.create_new_random(user)
     assert alias.email.endswith(EMAIL_DOMAIN)