move get_spam_score_async(), get_spam_score() to email/spam.py

This commit is contained in:
Son NK 2021-03-17 10:07:13 +01:00
parent f6d3172e3e
commit d1d81e6a6d
3 changed files with 64 additions and 55 deletions

0
app/email/__init__.py Normal file
View File

63
app/email/spam.py Normal file
View File

@ -0,0 +1,63 @@
import asyncio
import time
from email.message import Message
import aiospamc
from app.config import SPAMASSASSIN_HOST
from app.email_utils import to_bytes
from app.log import LOG
from app.models import EmailLog
from app.spamassassin_utils import SpamAssassin
async def get_spam_score_async(message: Message) -> float:
sa_input = to_bytes(message)
# Spamassassin requires to have an ending linebreak
if not sa_input.endswith(b"\n"):
LOG.d("add linebreak to spamassassin input")
sa_input += b"\n"
try:
# wait for at max 300s which is the default spamd timeout-child
response = await asyncio.wait_for(
aiospamc.check(sa_input, host=SPAMASSASSIN_HOST), timeout=300
)
return response.headers["Spam"].score
except asyncio.TimeoutError:
LOG.e("SpamAssassin timeout")
# return a negative score so the message is always considered as ham
return -999
except Exception:
LOG.e("SpamAssassin exception")
return -999
def get_spam_score(
message: Message, email_log: EmailLog, can_retry=True
) -> (float, dict):
"""
Return the spam score and spam report
"""
LOG.d("get spam score for %s", email_log)
sa_input = to_bytes(message)
# Spamassassin requires to have an ending linebreak
if not sa_input.endswith(b"\n"):
LOG.d("add linebreak to spamassassin input")
sa_input += b"\n"
try:
# wait for at max 300s which is the default spamd timeout-child
sa = SpamAssassin(sa_input, host=SPAMASSASSIN_HOST, timeout=300)
return sa.get_score(), sa.get_report_json()
except Exception:
if can_retry:
LOG.w("SpamAssassin exception, retry")
time.sleep(3)
return get_spam_score(message, email_log, can_retry=False)
else:
# return a negative score so the message is always considered as ham
LOG.exception("SpamAssassin exception, ignore spam check")
return -999, None

View File

@ -31,7 +31,6 @@ It should contain the following info:
""" """
import argparse import argparse
import asyncio
import email import email
import time import time
import uuid import uuid
@ -45,7 +44,6 @@ from io import BytesIO
from smtplib import SMTP, SMTPRecipientsRefused, SMTPServerDisconnected from smtplib import SMTP, SMTPRecipientsRefused, SMTPServerDisconnected
from typing import List, Tuple, Optional from typing import List, Tuple, Optional
import aiospamc
import arrow import arrow
import spf import spf
from aiosmtpd.controller import Controller from aiosmtpd.controller import Controller
@ -83,6 +81,7 @@ from app.config import (
POSTFIX_PORT_FORWARD, POSTFIX_PORT_FORWARD,
NOT_SEND_EMAIL, NOT_SEND_EMAIL,
) )
from app.email.spam import get_spam_score
from app.email_utils import ( from app.email_utils import (
send_email, send_email,
add_dkim_signature, add_dkim_signature,
@ -125,7 +124,6 @@ from app.models import (
TransactionalEmail, TransactionalEmail,
) )
from app.pgp_utils import PGPException, sign_data_with_pgpy, sign_data from app.pgp_utils import PGPException, sign_data_with_pgpy, sign_data
from app.spamassassin_utils import SpamAssassin
from app.utils import sanitize_email from app.utils import sanitize_email
from init_app import load_pgp_public_keys from init_app import load_pgp_public_keys
from server import create_app, create_light_app from server import create_app, create_light_app
@ -1672,58 +1670,6 @@ def handle_bounce(envelope, rcpt_to) -> str:
return "550 SL E26 Email cannot be forwarded to mailbox" return "550 SL E26 Email cannot be forwarded to mailbox"
async def get_spam_score_async(message: Message) -> float:
sa_input = to_bytes(message)
# Spamassassin requires to have an ending linebreak
if not sa_input.endswith(b"\n"):
LOG.d("add linebreak to spamassassin input")
sa_input += b"\n"
try:
# wait for at max 300s which is the default spamd timeout-child
response = await asyncio.wait_for(
aiospamc.check(sa_input, host=SPAMASSASSIN_HOST), timeout=300
)
return response.headers["Spam"].score
except asyncio.TimeoutError:
LOG.e("SpamAssassin timeout")
# return a negative score so the message is always considered as ham
return -999
except Exception:
LOG.e("SpamAssassin exception")
return -999
def get_spam_score(
message: Message, email_log: EmailLog, can_retry=True
) -> (float, dict):
"""
Return the spam score and spam report
"""
LOG.d("get spam score for %s", email_log)
sa_input = to_bytes(message)
# Spamassassin requires to have an ending linebreak
if not sa_input.endswith(b"\n"):
LOG.d("add linebreak to spamassassin input")
sa_input += b"\n"
try:
# wait for at max 300s which is the default spamd timeout-child
sa = SpamAssassin(sa_input, host=SPAMASSASSIN_HOST, timeout=300)
return sa.get_score(), sa.get_report_json()
except Exception:
if can_retry:
LOG.w("SpamAssassin exception, retry")
time.sleep(3)
return get_spam_score(message, email_log, can_retry=False)
else:
# return a negative score so the message is always considered as ham
LOG.exception("SpamAssassin exception, ignore spam check")
return -999, None
def sl_sendmail( def sl_sendmail(
from_addr, from_addr,
to_addr, to_addr,