[email] Fix email parsing in kibicara_mda
This commit is contained in:
parent
b8113c59ae
commit
1bfa7b6a41
|
@ -3,6 +3,8 @@
|
||||||
# SPDX-License-Identifier: 0BSD
|
# SPDX-License-Identifier: 0BSD
|
||||||
|
|
||||||
import email.parser
|
import email.parser
|
||||||
|
from email.policy import default
|
||||||
|
import email.message
|
||||||
import sys
|
import sys
|
||||||
import re
|
import re
|
||||||
import requests
|
import requests
|
||||||
|
@ -10,43 +12,102 @@ from logging import getLogger
|
||||||
from kibicara.model import Hood
|
from kibicara.model import Hood
|
||||||
from kibicara.platforms.email.model import Email
|
from kibicara.platforms.email.model import Email
|
||||||
import argparse
|
import argparse
|
||||||
|
from asyncio import run
|
||||||
|
from fastapi import status
|
||||||
|
from ormantic import NoMatch
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def async_main(mail=None, hood_name=None):
|
||||||
logger = getLogger(__name__)
|
logger = getLogger(__name__)
|
||||||
|
|
||||||
# the MDA passes the recipient address as command line argument
|
# the MDA passes the recipient address as command line argument
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("recipient_address")
|
if hood_name is None:
|
||||||
args = parser.parse_args()
|
parser.add_argument("recipient_address")
|
||||||
|
args = parser.parse_args()
|
||||||
|
# extract hood name from the envelope recipient address
|
||||||
|
hood_name = args.recipient_address.split('@')[0].lower()
|
||||||
|
|
||||||
# read mail from STDIN
|
if mail is None:
|
||||||
mailbytes = bytes(sys.stdin.read())
|
# read mail from STDIN
|
||||||
|
mail = bytes(sys.stdin.read(), encoding='ascii')
|
||||||
|
# parse plaintext to email.EmailMessage object
|
||||||
|
mail = email.parser.BytesParser(policy=default).parsebytes(mail)
|
||||||
|
else:
|
||||||
|
mail = email.parser.Parser(policy=default).parsestr(mail)
|
||||||
|
|
||||||
# parse plaintext to email.EmailMessage object
|
assert type(mail) == email.message.EmailMessage
|
||||||
myparser = email.parser.BytesParser()
|
|
||||||
mail = myparser.parsebytes(mailbytes)
|
|
||||||
|
|
||||||
# extract relevant data from mail
|
# extract relevant data from mail
|
||||||
for part in mail.walk():
|
body = mail.get_body(preferencelist=('plain', 'html'))
|
||||||
try:
|
if body['content-type'].subtype == 'plain':
|
||||||
text = part.get_body(('plain',))
|
text = str(body.get_content())
|
||||||
if not text:
|
elif body['content-type'].subtype == 'html':
|
||||||
text = re.sub(r'<[^>]*>', '', part.get_body(('html',)))
|
text = re.sub(r'<[^>]*>', '', body.get_content())
|
||||||
except Exception:
|
|
||||||
logger.info("No Body in this message part", exc_info=True)
|
try:
|
||||||
if not text:
|
text = str(text)
|
||||||
logger.error('No suitable message body')
|
except UnboundLocalError:
|
||||||
|
print('No suitable message body')
|
||||||
|
exit(1)
|
||||||
|
try:
|
||||||
|
hood = await Hood.objects.get(name=hood_name)
|
||||||
|
except NoMatch:
|
||||||
|
print('No hood with this name')
|
||||||
exit(1)
|
exit(1)
|
||||||
# extract hood name from the envelope recipient address
|
|
||||||
hood_name = args.recipient_address.split('@')[0].lower()
|
|
||||||
hood = await Hood.objects.get(name=hood_name)
|
|
||||||
email_row = await Email.objects.get(hood=hood)
|
email_row = await Email.objects.get(hood=hood)
|
||||||
body = {
|
body = {
|
||||||
'text': text,
|
'text': text,
|
||||||
'author': mail.get_unixfrom(),
|
'author': mail.get_unixfrom(),
|
||||||
'secret': email_row.secret,
|
'secret': email_row.secret,
|
||||||
}
|
}
|
||||||
requests.post(
|
response = requests.post(
|
||||||
'http://localhost:8000/api/hoods/%d/email/messages/' % (hood.id), json=body
|
'http://localhost:8000/api/hoods/%d/email/messages/' % hood.id, json=body
|
||||||
)
|
)
|
||||||
|
print("Request sent:")
|
||||||
|
if response.status_code == status.HTTP_201_CREATED:
|
||||||
|
exit(0)
|
||||||
|
elif response.status_code == status.HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS:
|
||||||
|
print("Message was't accepted: " + text)
|
||||||
|
elif response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY:
|
||||||
|
print("Malformed request: " + str(response.json()))
|
||||||
|
elif response.status_code == status.HTTP_401_UNAUTHORIZED:
|
||||||
|
logger.error('Wrong API secret. kibicara_mda seems to be misconfigured')
|
||||||
|
else:
|
||||||
|
print(str(response.status_code))
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
run(async_main())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__.endswith('kibicara_mda'):
|
||||||
|
mail = """From test@example.com Tue Jun 16 15:33:19 2020
|
||||||
|
Return-path: <test@example.com>
|
||||||
|
Envelope-to: hood@localhost
|
||||||
|
Delivery-date: Tue, 16 Jun 2020 15:33:19 +0200
|
||||||
|
Received: from [23.143.35.123] (helo=example.com)
|
||||||
|
by example.com with smtp (Exim 4.89)
|
||||||
|
(envelope-from <test@example.com>)
|
||||||
|
id 1jlC1e-0005ro-PL
|
||||||
|
for hood@localhost; Tue, 16 Jun 2020 15:33:19 +0200
|
||||||
|
Message-ID: <B5F50812.F55DFD8B@example.com>
|
||||||
|
Date: Tue, 16 Jun 2020 06:53:19 -0700
|
||||||
|
Reply-To: "Test" <test@example.com>
|
||||||
|
From: "Test" <test@example.com>
|
||||||
|
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.1.17) Gecko/20080914 Thunderbird/2.0.0.17
|
||||||
|
MIME-Version: 1.0
|
||||||
|
To: <hood@localhost>
|
||||||
|
Subject: Chat: test
|
||||||
|
Content-Type: multipart/mixed; boundary="AqNPlAX243a8sip3B7kXv8UKD8wuti"
|
||||||
|
|
||||||
|
|
||||||
|
--AqNPlAX243a8sip3B7kXv8UKD8wuti
|
||||||
|
Content-Type: text/plain; charset=utf-8
|
||||||
|
|
||||||
|
test
|
||||||
|
|
||||||
|
--AqNPlAX243a8sip3B7kXv8UKD8wuti--
|
||||||
|
"""
|
||||||
|
run(async_main(mail=mail, hood_name='hood'))
|
||||||
|
|
|
@ -24,6 +24,7 @@ class EmailBot(Censor):
|
||||||
""" Loop which waits for new messages and sends emails to all subscribers. """
|
""" Loop which waits for new messages and sends emails to all subscribers. """
|
||||||
while True:
|
while True:
|
||||||
message = await self.receive()
|
message = await self.receive()
|
||||||
|
logger.info("Received Email from %s: %s" % (message.author, message.text))
|
||||||
for subscriber in EmailSubscribers.objects.filter(hood=self.hood.id):
|
for subscriber in EmailSubscribers.objects.filter(hood=self.hood.id):
|
||||||
token = to_token(email=subscriber.email, hood=self.hood.id)
|
token = to_token(email=subscriber.email, hood=self.hood.id)
|
||||||
unsubscribe_link = (
|
unsubscribe_link = (
|
||||||
|
|
Loading…
Reference in a new issue