I want to receive mails from mailgun in a Django web application. I have problem with parsing the data to the form. As you can see, in the froms.py there is a field_map, to convert the fields Mailgun sends to the model fields. This is not working. All fields that are not converted I receive, but for example the from field I cannot retrieve. I have installed Django 1.8 and Python2.7. The code is fromhttps://github.com/hedberg/django-mailgun-incoming I think this would work for Django < 1.8, because in Django 1.8 is introduced the obligation to specify the fields. In older versions, omitting both fields and exclude resulted in a form with all the model’s fields. Doing this now raises an ImproperlyConfigured exception.Hope someone can help me. Thanks in advance
Here is the link to Mailgun for more information https://documentation.mailgun.com/user_manual.html#routes
from django import forms
from models import EmailBaseModel
class EmailForm(forms.ModelForm):
field_map = {'from_str':'from',
'body_plain':'body-plain',
'body_html':'body-html',
'stripped_text':'stripped-text',
'stripped_html':'stripped-html',
'message_headers':'message-headers',
'stripped_signature':'stripped-signature',
'content_id_map':'content-id-map'}
class Meta:
# model = EmailBaseModel
fields = '__all__'
def __init__(self, *args, **kwargs):
super(EmailForm, self).__init__(*args, **kwargs)
for (field_name, form_key) in self.field_map.items():
self.fields[form_key] = self.fields[field_name]
del self.fields[field_name]
self.fields['attachment-count'] = forms.IntegerField(required=False)
def clean(self):
for (field_name, form_key) in self.field_map.items():
if form_key in self.cleaned_data:
self.cleaned_data[field_name] = self.cleaned_data[form_key]
return self.cleaned_data# -*- coding: utf-8 -*-
import hashlib, hmac
import logging
#import pdb
from django.conf import settings
from django.http import HttpResponse, HttpResponseBadRequest
from django.forms.models import modelform_factory
from django.views.generic.base import View
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from mailgun_incoming.models import Attachment, IncomingEmail
from mailgun_incoming.signals import email_received
from mailgun_incoming.forms import EmailForm
logger = logging.getLogger(__name__)
API_KEY = getattr(settings, "MAILGUN_ACCESS_KEY", "")
VERIFY_SIGNATURE = getattr(settings, "MAILGUN_VERIFY_INCOMING", API_KEY!="")
class Incoming(View):
#pdb.set_trace()
email_model = IncomingEmail
attachment_model = Attachment
form = EmailForm
api_key = API_KEY
verify = VERIFY_SIGNATURE
def get_form(self):
return modelform_factory(self.email_model, form=self.form)
@method_decorator(csrf_exempt)
def dispatch(self, *args, **kwargs):
return super(Incoming, self).dispatch(*args, **kwargs)
def post(self, request, *args, **kwargs):
if self.verify:
verified = self.verify_signature(request.POST.get('token',''),
request.POST.get('timestamp',''),
request.POST.get('signature',''))
if not verified:
logger.debug("Signature verification failed. Email posted from %s. %s" % (
request.META.get('REMOTE_ADDR','<no remote addr>'),
request.POST.get('subject', '')))
return HttpResponseBadRequest("Invalid signature")
form = self.get_form()(request.POST)
if form.is_valid():
#save email
email = form.save()
#save attachments
attachments = []
if form.cleaned_data.get('attachment-count',0):
attachments = []
#reverse mapping in content_ids dict
content_ids = dict((attnr,cid) for cid,attnr in (email.content_ids or {}).iteritems())
i = 1
for file in request.FILES.values():
attachment = self.attachment_model(email=email, file=file, content_id=content_ids.get('attachment-{0!s}'.format(i),'')).save()
attachments.append(attachment)
i += 1
self.handle_email(email, attachments=attachments)
else:
logger.debug("Received email message contained errors. %s" % form.errors)
return HttpResponse("OK")
def handle_email(self, email, attachments=None):
email_received.send(sender=self.email_model, instance=email, attachments=attachments or [])
def verify_signature(self, token, timestamp, signature):
return signature == hmac.new(key=self.api_key,
msg='{0}{1}'.format(timestamp, token),
digestmod=hashlib.sha256).hexdigest()