import re import chardet import logging from functools import reduce from email import policy from email.parser import BytesParser from email.message import EmailMessage from django.conf import settings from django.contrib.auth.models import User from django.core.exceptions import PermissionDenied from django.http import Http404, HttpResponse from django.shortcuts import get_object_or_404 from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_http_methods from .models import Message from .utils import hexdigest_sha256 @csrf_exempt @require_http_methods(["POST"]) def email_recv(request): if not hasattr(settings, 'REPLY_EMAIL') \ or not hasattr(settings, 'REPLY_KEY'): return HttpResponse(status=501) # Not Implemented key = request.POST.get('key').strip() if key != settings.REPLY_KEY: raise PermissionDenied if 'email' not in request.FILES: return HttpResponse(status=400) # Bad Request msg = request.FILES['email'] msg = BytesParser(policy=policy.default).parsebytes(msg.read()) body = msg.get_body(preferencelist=('plain',)) content = body.get_payload(decode=True) try: content = content.decode(body.get_content_charset()) except Exception: encoding = chardet.detect(content)['encoding'] content = content.decode(encoding) addr = settings.REPLY_EMAIL pos = addr.find('@') name = addr[:pos] domain = addr[pos+1:] regexp = '^%s\+(?P[a-z0-9]{12})(?P[a-z0-9]{60})(?P[a-z0-9]{12})@%s$' % (name, domain) p = re.compile(regexp) m = None addrs = map(lambda x: x.split(',') if x else [], [msg.get('To'), msg.get('Cc')]) addrs = reduce(lambda x, y: x + y, addrs) for _mto in map(lambda x: x.strip(), addrs): m = p.match(_mto) if m: break if not m: # no one matches raise Http404 author = get_object_or_404(User, profile__email_token=m.group('dest')) message = get_object_or_404(Message, token=m.group('token')) key = hexdigest_sha256(settings.SECRET_KEY, message.token, author.pk)[0:12] if key != m.group('key'): raise PermissionDenied answer = Message(conversation=message.conversation, author=author, content=content) answer.save() return HttpResponse()