brack3t / Djrill

[INACTIVE/UNMAINTAINED] Djrill is an email backend and new message class for Django users that want to take advantage of the Mandrill transactional email service from MailChimp.
BSD 3-Clause "New" or "Revised" License
319 stars 64 forks source link

New Djrill admin #102

Closed jdruiter closed 8 years ago

jdruiter commented 9 years ago

A client asked me a feature: to see the message sent-status in the django admin. It was great to see this feature in Drill.

Logging into Mandrill to look up a message status is not ideal. Definitely not for a client. Mandirll also keeps messages only for 30 or 90 days.

I've found no existing django solution yet. Django mailer and django-mailer2 don't do it. Djrill showing me was great. Alas, the interface is not showing me message contents, and soon it will be removed in 2.0.

There were good reasons for removing the Djrill admin site. But there's also good reason for adding a new lightweight one.

How would it be possible to add a lightweight admin that shows a list of messages sent?

Requirements:

I'm willing to contribute

medmunds commented 9 years ago

Djrill's current admin simply calls existing Mandrill APIs and then formats the JSON results in a nice web page, inside Django's admin site. Djrill is definitely not keeping track of sent messages or their status on its own.

It would be pretty straightforward to copy Djrill's admin into your own app, and add a view for message status as reported by Mandrill (e.g., using their messages/search API). That's about as lightweight as it gets, but I'm not sure it meets your other requirements.

If you want to keep track of all of the messages ever sent (beyond the 30-90 days that Mandrill maintains), you'd need to add Django models to store the message information in the database. I feel that's beyond the scope of Djrill, which is meant to be a relatively thin translation layer between the Django and Mandrill email APIs.

But django-mailer already does a lot of this -- it keeps track of all messages sent using any Django email backend (including Djrill), as models in your database. It wraps the backend send in a try/catch, so that it can retry sends that didn't go through the first time. You can view the message log in Django admin -- including whether each message was successfully handed off to Mandrill.

I've been using django-mailer together with Djrill for a few years now, and (with minor wrinkles) it seems to work fine. What it doesn't do is keep track of the Mandrill message-id for sent emails, so there's no way to look up a message's detailed status, open and clickthrough, etc. in Mandrill.

You might consider building on django-mailer to add the functionality you need: add a model to keep track of the Mandrill message-id (with a OneToOneField relating it to django-mailer's MessageLog model), and a custom admin details view that displays the HTML from the original message (stored in MessageLog.message_data) and that queries Mandrill for clickthrough, etc.

jdruiter commented 9 years ago

Thanks for your answer.

I see two ways to achieve this:

Option 1) Extending Djrill admin with clickable message content. That's the minimum requirement. it requires an extra API call to Mandrill and change of the views.

Option 2) Extending django-mailer with a Mandrill message status. I could copy some API calls from Djrill but for the rest have to do most integration myself.

Which path is best from your perspective? I'm kinda hesitating to extend django-mailer because it would fragment the package more and create another project to maintain. Mandrill is not something everyone uses (though should maybe) so It wouldn't be accepted to integrate into the main Pinax package.

medmunds commented 9 years ago

I'm actually suggesting an option 3: create your own app that has exactly the features you (or your client) want, and add that to your Django INSTALLED_APPS alongside djrill (and alongside django-mailer, too, if you decide its functionality is useful for your needs).

One of the nice things about Django's architecture is it encourages mixing and matching small, focused packages (Django "apps") within your project. So you can make an app that just implements these admin features -- nothing more, nothing less.

Let's say your new app would be called "django-mandrill-admin". (Creative, I know.) And for simplicity, let's say it's just going to add an admin view that displays a list of sent messages from Mandrill's search API and lets the user click them to see details. You can always add more views later.

django-mandrill-admin doesn't really care whether or not Djrill is installed, right? It could probably use the same settings.MANDRILL_API_KEY for calling Mandrill's JSON APIs, but there's nothing in Djrill's own code you'd need. (Bonus: that means your app would work fine with Djrill 2.0, when we drop Djrill's admin views. And it would work equally well with Mandrill SMTP integration, if you choose not to use Djrill at all.)

To add arbitrary HTML views to Django's admin, you'll want something like jsocol's django-adminplus. (Djrill borrowed its admin view code from that project. There's a Django 1.8 branch under active development.) Note that django-adminplus is another Django reusable app you add to your INSTALLED_APPS and then build alongside -- you don't need to fork it or anything like that.

The sent-messages list implementation is something like this (untested code; error handling omitted):

@admin.site.register_view('mandrill_admin_sent')  # using django-adminplus
class SentMessagesView(TemplateView):
    template_name = "mandrill_admin/sent.html"

    def get_context_data(self, **kwargs):
        # Call Mandrill messages/search API, and add result to template context
        response = requests.post(
            "https://mandrillapp.com/api/1.0/messages/search.json",
            data = {"key": settings.MANDRILL_API_KEY})   # add additional params here
        context = super(SentMessagesView, self).get_context_data(**kwargs)
        context['sent_messages'] = response.json()
        return context

And your mandrill_admin/sent.html template could then iterate over sent_messages to build the list. (Here's an example from Djrill's admin -- it's a tags list, rather than message list, but you get the idea.)

Then to implement a MessageDetailView, you'd do something similar, calling Mandrill's messages/info and/or messages/content APIs.

Finally, once you come up with something you like, you could even release it as a Django reusable app. (And if you do, we'd be happy to link to it from the Djrill docs.)

medmunds commented 9 years ago

Also, I got an out-of-band question about why someone might want to use both django-mailer and Djrill. The answer is, they serve different purposes. (And since they're both designed as mix-and-match Django reusable apps, it's easy to use them together.)

django-mailer solves two problems: (1) making email sending asynchronous, so that it doesn't delay responding to users' http requests, and (2) retrying email sends later if the first attempt fails. (Although Mandrill's uptime is excellent, the connectivity between my servers and Mandrill isn't always, because, internet. So catching network errors and retrying them later is important.)

Djrill solves a different problem: sending Django EmailMessages through Mandrill's API (rather than, say, through SMTP). It doesn't care how you're scheduling sending or handling error retries; Djrill's only purpose is talking to the Mandrill API.

The project where I'm using both adopted django-mailer long before we started using Mandrill. But since django-mailer works fine with Djrill, there's never been a reason to switch. A lot of people use Celery for async Django email, which also works fine with Djrill. And there's at least one other option that works with pluggable email backends.

jdruiter commented 9 years ago

Thanks a lot for the information and suggestions. I can take it from there to develop it