Create send_email_with_rate_control(): same as send_email() but with rate control

This commit is contained in:
Son NK 2020-05-09 20:43:17 +02:00
parent 7fdef16f37
commit d9f1fb9130
3 changed files with 70 additions and 1 deletions

View file

@ -254,3 +254,15 @@ with open(get_abs_path(DISPOSABLE_FILE_PATH), "r") as f:
APPLE_API_SECRET = os.environ.get("APPLE_API_SECRET") APPLE_API_SECRET = os.environ.get("APPLE_API_SECRET")
# for Mac App # for Mac App
MACAPP_APPLE_API_SECRET = os.environ.get("MACAPP_APPLE_API_SECRET") MACAPP_APPLE_API_SECRET = os.environ.get("MACAPP_APPLE_API_SECRET")
# maximal number of alerts that can be sent to the same email in 24h
MAX_ALERT_24H = 4
# When a reverse-alias receives emails from un unknown mailbox
ALERT_REVERSE_ALIAS_UNKNOWN_MAILBOX = "reverse_alias_unknown_mailbox"
# When a forwarding email is bounced
ALERT_BOUNCE_EMAIL = "bounce"
# When a forwarding email is detected as spam
ALERT_SPAM_EMAIL = "spam"

View file

@ -8,6 +8,7 @@ from email.utils import make_msgid, formatdate, parseaddr
from smtplib import SMTP from smtplib import SMTP
from typing import Optional from typing import Optional
import arrow
import dkim import dkim
from jinja2 import Environment, FileSystemLoader from jinja2 import Environment, FileSystemLoader
@ -24,10 +25,12 @@ from app.config import (
POSTFIX_SUBMISSION_TLS, POSTFIX_SUBMISSION_TLS,
MAX_NB_EMAIL_FREE_PLAN, MAX_NB_EMAIL_FREE_PLAN,
DISPOSABLE_EMAIL_DOMAINS, DISPOSABLE_EMAIL_DOMAINS,
MAX_ALERT_24H,
) )
from app.dns_utils import get_mx_domains from app.dns_utils import get_mx_domains
from app.extensions import db
from app.log import LOG from app.log import LOG
from app.models import Mailbox, User from app.models import Mailbox, User, SentAlert
def render(template_name, **kwargs) -> str: def render(template_name, **kwargs) -> str:
@ -235,6 +238,43 @@ def send_email(
smtp.sendmail(SUPPORT_EMAIL, to_email, msg_raw) smtp.sendmail(SUPPORT_EMAIL, to_email, msg_raw)
def send_email_with_rate_control(
user: User,
alert_type: str,
to_email: str,
subject,
plaintext,
html=None,
bounced_email: Optional[Message] = None,
) -> bool:
"""Same as send_email with rate control over alert_type.
For now no more than _MAX_ALERT_24h alert can be sent in the last 24h
Return true if the email is sent, otherwise False
"""
to_email = to_email.lower().strip()
one_day_ago = arrow.now().shift(days=-1)
nb_alert = (
SentAlert.query.filter_by(alert_type=alert_type, to_email=to_email)
.filter(SentAlert.created_at > one_day_ago)
.count()
)
if nb_alert > MAX_ALERT_24H:
LOG.error(
"%s emails were sent to %s in the last 24h, alert type %s",
nb_alert,
to_email,
alert_type,
)
return False
SentAlert.create(user_id=user.id, alert_type=alert_type, to_email=to_email)
db.session.commit()
send_email(to_email, subject, plaintext, html, bounced_email)
return True
def get_email_local_part(address): def get_email_local_part(address):
""" """
Get the local part from email Get the local part from email

View file

@ -1,5 +1,6 @@
from email.message import EmailMessage from email.message import EmailMessage
from app.config import MAX_ALERT_24H
from app.email_utils import ( from app.email_utils import (
get_email_domain_part, get_email_domain_part,
email_belongs_to_alias_domains, email_belongs_to_alias_domains,
@ -7,6 +8,7 @@ from app.email_utils import (
delete_header, delete_header,
add_or_replace_header, add_or_replace_header,
parseaddr_unicode, parseaddr_unicode,
send_email_with_rate_control,
) )
from app.extensions import db from app.extensions import db
from app.models import User, CustomDomain from app.models import User, CustomDomain
@ -101,3 +103,18 @@ def test_parseaddr_unicode():
"pöstal", "pöstal",
"abcd@gmail.com", "abcd@gmail.com",
) )
def test_send_email_with_rate_control(flask_client):
user = User.create(
email="a@b.c", password="password", name="Test User", activated=True
)
db.session.commit()
for _ in range(MAX_ALERT_24H + 1):
assert send_email_with_rate_control(
user, "test alert type", "abcd@gmail.com", "subject", "plaintext"
)
assert not send_email_with_rate_control(
user, "test alert type", "abcd@gmail.com", "subject", "plaintext"
)