From 8268568f0869f8cdb7f39189b0db12705c2626ee Mon Sep 17 00:00:00 2001 From: Son NK <> Date: Mon, 12 Oct 2020 13:28:21 +0200 Subject: [PATCH] add mailbox.disabled column. Disable a mailbox if it fails tests for 10 days consecutive. --- app/models.py | 3 ++ cron.py | 34 ++++++++++++++++--- email_handler.py | 4 +++ .../versions/2020_101213_b17afc77ba83_.py | 29 ++++++++++++++++ .../disable-mailbox-warning.html | 32 +++++++++++++++++ .../transactional/disable-mailbox-warning.txt | 16 +++++++++ .../emails/transactional/disable-mailbox.html | 32 +++++++++++++++++ .../emails/transactional/disable-mailbox.txt | 17 ++++++++++ 8 files changed, 163 insertions(+), 4 deletions(-) create mode 100644 migrations/versions/2020_101213_b17afc77ba83_.py create mode 100644 templates/emails/transactional/disable-mailbox-warning.html create mode 100644 templates/emails/transactional/disable-mailbox-warning.txt create mode 100644 templates/emails/transactional/disable-mailbox.html create mode 100644 templates/emails/transactional/disable-mailbox.txt diff --git a/app/models.py b/app/models.py index 9b558a9a..42c28961 100644 --- a/app/models.py +++ b/app/models.py @@ -1568,6 +1568,9 @@ class Mailbox(db.Model, ModelMixin): db.Integer, default=0, server_default="0", nullable=False ) + # a mailbox can be disabled if it can't be reached + disabled = db.Column(db.Boolean, default=False, nullable=False, server_default="0") + __table_args__ = (db.UniqueConstraint("user_id", "email", name="uq_mailbox_user"),) user = db.relationship(User, foreign_keys=[user_id]) diff --git a/cron.py b/cron.py index c49099d3..66d04e75 100644 --- a/cron.py +++ b/cron.py @@ -293,7 +293,11 @@ def sanity_check(): Different sanity checks - detect if there's mailbox that's using a invalid domain """ - mailbox_ids = db.session.query(Mailbox.id).filter(Mailbox.verified == True).all() + mailbox_ids = ( + db.session.query(Mailbox.id) + .filter(Mailbox.verified == True, Mailbox.disabled == False) + .all() + ) mailbox_ids = [e[0] for e in mailbox_ids] # iterate over id instead of mailbox directly @@ -310,13 +314,35 @@ def sanity_check(): if not email_domain_can_be_used_as_mailbox(mailbox.email): mailbox.nb_failed_checks += 1 nb_email_log = nb_email_log_for_mailbox(mailbox) + log_func = LOG.warning + + # send a warning + if mailbox.nb_failed_checks == 5: + if mailbox.user.email != mailbox.email: + send_email( + mailbox.user.email, + f"Mailbox {mailbox.email} is disabled", + render( + "transactional/disable-mailbox-warning.txt", mailbox=mailbox + ), + render( + "transactional/disable-mailbox-warning.html", + mailbox=mailbox, + ), + ) # alert if too much fail and nb_email_log > 100 if mailbox.nb_failed_checks > 10 and nb_email_log > 100: log_func = LOG.exception - mailbox.verified = False - else: - log_func = LOG.warning + mailbox.disabled = True + + if mailbox.user.email != mailbox.email: + send_email( + mailbox.user.email, + f"Mailbox {mailbox.email} is disabled", + render("transactional/disable-mailbox.txt", mailbox=mailbox), + render("transactional/disable-mailbox.html", mailbox=mailbox), + ) log_func( "issue with mailbox %s domain. #alias %s, nb email log %s", diff --git a/email_handler.py b/email_handler.py index ea5f6553..1b256127 100644 --- a/email_handler.py +++ b/email_handler.py @@ -533,6 +533,10 @@ def forward_email_to_mailbox( ) -> (bool, str): LOG.d("Forward %s -> %s -> %s", contact, alias, mailbox) + if mailbox.disabled: + LOG.debug("%s disabled, do not forward") + return False, "550 SL E21 Disabled mailbox" + # sanity check: make sure mailbox is not actually an alias if get_email_domain_part(alias.email) == get_email_domain_part(mailbox.email): LOG.warning( diff --git a/migrations/versions/2020_101213_b17afc77ba83_.py b/migrations/versions/2020_101213_b17afc77ba83_.py new file mode 100644 index 00000000..1fe34058 --- /dev/null +++ b/migrations/versions/2020_101213_b17afc77ba83_.py @@ -0,0 +1,29 @@ +"""empty message + +Revision ID: b17afc77ba83 +Revises: 32b00d06d892 +Create Date: 2020-10-12 13:24:36.666256 + +""" +import sqlalchemy_utils +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'b17afc77ba83' +down_revision = '32b00d06d892' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('mailbox', sa.Column('disabled', sa.Boolean(), server_default='0', nullable=False)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('mailbox', 'disabled') + # ### end Alembic commands ### diff --git a/templates/emails/transactional/disable-mailbox-warning.html b/templates/emails/transactional/disable-mailbox-warning.html new file mode 100644 index 00000000..857d34a3 --- /dev/null +++ b/templates/emails/transactional/disable-mailbox-warning.html @@ -0,0 +1,32 @@ +{% extends "base.html" %} + +{% block content %} + {% call text() %} +

+ Issues with {{ mailbox.email }}. +

+ {% endcall %} + + {% call text() %} + We have detected that your mailbox can't reliably receive emails from SimpleLogin for a consecutive period of time.
+ The mailbox will be disabled in 5 days if the problem isn't solved by then. + {% endcall %} + + {% call text() %} + Please note that a mailbox must be a final email address and cannot be + another email alias or a disposable email address. + {% endcall %} + + {% call text() %} + If you have any question, you can reach out to us by replying to this email. + {% endcall %} + + {% call text() %} + Best,
+ SimpleLogin Team. + {% endcall %} + + +{% endblock %} + + diff --git a/templates/emails/transactional/disable-mailbox-warning.txt b/templates/emails/transactional/disable-mailbox-warning.txt new file mode 100644 index 00000000..d567f979 --- /dev/null +++ b/templates/emails/transactional/disable-mailbox-warning.txt @@ -0,0 +1,16 @@ +Issues with {{ mailbox.email }}. + +We have detected that your mailbox cannot reliably receive emails from SimpleLogin for a consecutive period of time. +The mailbox will be disabled in 5 days if the problem isn't solved by then. + +Please note that a mailbox must be a "final" email address and cannot be +another email alias or a disposable email address. + +If you have any question, you can reach out to us by replying to this email. + +Best, +SimpleLogin Team. + + + + diff --git a/templates/emails/transactional/disable-mailbox.html b/templates/emails/transactional/disable-mailbox.html new file mode 100644 index 00000000..8f1a1613 --- /dev/null +++ b/templates/emails/transactional/disable-mailbox.html @@ -0,0 +1,32 @@ +{% extends "base.html" %} + +{% block content %} + {% call text() %} +

+ {{ mailbox.email }} is disabled. +

+ {% endcall %} + + {% call text() %} + We have detected that your mailbox can't reliably receive emails from SimpleLogin for a consecutive period of time.
+ The mailbox has been therefore disabled. + {% endcall %} + + {% call text() %} + Please note that a mailbox must be a final email address and cannot be + another email alias or a disposable email address. + {% endcall %} + + {% call text() %} + If you have any question, you can reach out to us by replying to this email. + {% endcall %} + + {% call text() %} + Best,
+ SimpleLogin Team. + {% endcall %} + + +{% endblock %} + + diff --git a/templates/emails/transactional/disable-mailbox.txt b/templates/emails/transactional/disable-mailbox.txt new file mode 100644 index 00000000..06aecace --- /dev/null +++ b/templates/emails/transactional/disable-mailbox.txt @@ -0,0 +1,17 @@ +{{ mailbox.email }} is disabled. + +We have detected that your mailbox cannot reliably receive emails from SimpleLogin for a consecutive period of time. +The mailbox has been therefore disabled. +You can re-enable it by going to the mailbox page. + +Please note that a mailbox must be a "final" email address and cannot be +another email alias or a disposable email address. + +If you have any question, you can reach out to us by replying to this email. + +Best, +SimpleLogin Team. + + + +