Django email backends and webhooks for Amazon SES, Mailgun, Mailjet, Postmark, SendGrid, Sendinblue, SparkPost and more

Overview

Anymail: Django email integration for transactional ESPs

Anymail integrates several transactional email service providers (ESPs) into Django, with a consistent API that lets you use ESP-added features without locking your code to a particular ESP.

It currently fully supports Amazon SES, Mailgun, Mailjet, Postmark, SendinBlue, SendGrid, and SparkPost, and has limited support for Mandrill.

Anymail normalizes ESP functionality so it "just works" with Django's built-in django.core.mail package. It includes:

  • Support for HTML, attachments, extra headers, and other features of Django's built-in email
  • Extensions that make it easy to use extra ESP functionality, like tags, metadata, and tracking, with code that's portable between ESPs
  • Simplified inline images for HTML email
  • Normalized sent-message status and tracking notification, by connecting your ESP's webhooks to Django signals
  • "Batch transactional" sends using your ESP's merge and template features
  • Inbound message support, to receive email through your ESP's webhooks, with simplified, portable access to attachments and other inbound content

Anymail maintains compatibility with all Django versions that are in mainstream or extended support, plus (usually) a few older Django versions, and is extensively tested on all Python versions supported by Django. (Even-older Django versions may still be covered by an Anymail extended support release; consult the changelog for details.)

Anymail releases follow semantic versioning. The package is released under the BSD license.

build status in GitHub Actions documentation on ReadTheDocs

Resources

Anymail 1-2-3

Here's how to send a message. This example uses Mailgun, but you can substitute Mailjet or Postmark or SendGrid or SparkPost or any other supported ESP where you see "mailgun":

  1. Install Anymail from PyPI:

    $ pip install "django-anymail[mailgun]"

    (The [mailgun] part installs any additional packages needed for that ESP. Mailgun doesn't have any, but some other ESPs do.)

  2. Edit your project's settings.py:

    ", "MAILGUN_SENDER_DOMAIN": 'mg.example.com', # your Mailgun domain, if needed } EMAIL_BACKEND = "anymail.backends.mailgun.EmailBackend" # or sendgrid.EmailBackend, or... DEFAULT_FROM_EMAIL = "[email protected]" # if you don't already have this in settings SERVER_EMAIL = "[email protected]" # ditto (default from-email for Django errors) ">
    INSTALLED_APPS = [
        # ...
        "anymail",
        # ...
    ]
    
    ANYMAIL = {
        # (exact settings here depend on your ESP...)
        "MAILGUN_API_KEY": "
         
          "
         ,
        "MAILGUN_SENDER_DOMAIN": 'mg.example.com',  # your Mailgun domain, if needed
    }
    EMAIL_BACKEND = "anymail.backends.mailgun.EmailBackend"  # or sendgrid.EmailBackend, or...
    DEFAULT_FROM_EMAIL = "[email protected]"  # if you don't already have this in settings
    SERVER_EMAIL = "[email protected]"  # ditto (default from-email for Django errors)
  3. Now the regular Django email functions will send through your chosen ESP:

    ", ["[email protected]"]) ">
    from django.core.mail import send_mail
    
    send_mail("It works!", "This will get sent through Mailgun",
              "Anymail Sender 
         
          "
         , ["[email protected]"])

    You could send an HTML message, complete with an inline image, custom tags and metadata:

    ", "[email protected]"], reply_to=["Helpdesk "]) # Include an inline image in the html: logo_cid = attach_inline_image_file(msg, "/path/to/logo.jpg") html = """ Logo

    Please activate your account

    """.format(logo_cid=logo_cid) msg.attach_alternative(html, "text/html") # Optional Anymail extensions: msg.metadata = {"user_id": "8675309", "experiment_variation": 1} msg.tags = ["activation", "onboarding"] msg.track_clicks = True # Send it: msg.send() ">
    from django.core.mail import EmailMultiAlternatives
    from anymail.message import attach_inline_image_file
    
    msg = EmailMultiAlternatives(
        subject="Please activate your account",
        body="Click to activate your account: https://example.com/activate",
        from_email="Example 
          
           "
          ,
        to=["New User 
          
           "
          , "[email protected]"],
        reply_to=["Helpdesk 
          
           "
          ])
    
    # Include an inline image in the html:
    logo_cid = attach_inline_image_file(msg, "/path/to/logo.jpg")
    html = """Logo
              

    Please activate your account

    """
    .format(logo_cid=logo_cid) msg.attach_alternative(html, "text/html") # Optional Anymail extensions: msg.metadata = {"user_id": "8675309", "experiment_variation": 1} msg.tags = ["activation", "onboarding"] msg.track_clicks = True # Send it: msg.send()

See the full documentation for more features and options, including receiving messages and tracking sent message status.

Comments
  • Add Postal support

    Add Postal support

    This is a very bare-bone implementation for the self-hosted Postal platform.

    About Postal:

    Postal is a complete and fully featured mail server for use by websites & web servers. Think Sendgrid, Mailgun or Postmark but open source and ready for you to run on your own servers.

    We use this draft implementation since a few days to handle emails for our karrot.world web app. Before we used SparkPost via anymail. I had good experiences with anymail so far, that's why I'm keen on using it. I'll improve this implementation during the next weeks as I find time. I'm happy about early feedback!

    To do:

    • [x] figure out how to do webhook authentication with Postal
    • [ ] support track_clicks and track_opens
    • [x] add backend tests
    • [x] add webhook tests
    • [x] add docs
    • [x] integration tests?
    new ESP esp:Postal 
    opened by tiltec 20
  • Support for SparkPost

    Support for SparkPost

    I just seemlessly migrated from djrill to django-anymail. Thanks for making it so easy!

    Now I'm looking to change ESP from Mandrill, and have found SparkPost to offer a very generous number of free emails, and a very similar user interface to Mandrill. Not only that, but they have a tool to migrate templates.

    It would be great if it were supported by django-anymail.

    Thanks.

    feature/enhancement esp:SparkPost 
    opened by ojwoodford 17
  • MultiValueDictKeyError in inbound email because of mismatch in count and actual files

    MultiValueDictKeyError in inbound email because of mismatch in count and actual files

    We are using Anymail 8.5, Django 3.2.12, Python 3.9.1 and have for a while been getting MultiValueDictKeyError ( in request.FILES[att_id] ) on some inbound Mailgun emails here https://github.com/anymail/django-anymail/blob/main/anymail/webhooks/mailgun.py#L406

    attachments = [
        AnymailInboundMessage.construct_attachment_from_uploaded_file(
            request.FILES[att_id], content_id=att_cids.get(att_id, None))
        for att_id in att_ids
    ]
    

    It seems request.POST[”attachment-count”] doesn’t match number of files in request.FILES and attachment-count doesn’t match number of attachment-%d. I don’t know if this is Mailgun removing some files or why, but maybe we could make Anymail handle it. We are seeing quite a few inbound mails not coming through at all because of this mismatch in counts. After all it would be better to have them come through with missing attachments rather than not coming at all, perhaps with an added flag of missing attachement so each implementation can handle potentially missing attachments.

    Below is an example of the relevant section of the request.POST content. Attachment-count (5), content-id-map (3) and actual attachment keys (2) don’t match.

    {
        'attachment-1': ['”BINARY_CONTENT”], 
        'attachment-2': [”BINARY_CONTENT”], 
        'attachment-count': ['5'], 
        'content-id-map': ['{"":"attachment-1","":"attachment-2","":"attachment-3"}'], 
    }
    
    bug esp:Mailgun esp:SendGrid 
    opened by erikdrums 16
  • Sendgrid: charset of text attachment is always iso-8859-1

    Sendgrid: charset of text attachment is always iso-8859-1

    • Anymail version Latest, 6.0.1

    • ESP (Mailgun, SendGrid, etc.) Sendgrid

    • Your ANYMAIL settings (change secrets to "redacted") Default

    • Versions of Django, requests, python django==1.11.20 requests==2.20.0 python==3.6.8

    • Exact error message and/or stack trace I'm sending an icalendar (ICS) file as attachment. The file's content is text (I don't think the exact content is relevant here, just note that there are some non-ascii chars around, like ü, and ä):

    BEGIN:VCALENDAR
    VERSION:2.0
    PRODID:-//flatfox//flatfox.ch//
    METHOD:REQUEST
    BEGIN:VEVENT
    SUMMARY:Viewing at Schreinerstrasse 64\, 8004 Zürich
    DTSTART;VALUE=DATE-TIME:20190526T150000Z
    DTEND;VALUE=DATE-TIME:20190526T153000Z
    DTSTAMP;VALUE=DATE-TIME:20190523T121031Z
    UID:[email protected]
    SEQUENCE:9
    ATTENDEE;CN="Bernhard Mäder";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED;ROLE=REQ
     -PARTICIPANT;RSVP=FALSE;X-NUM-GUESTS=0:MAILTO:<some_email>@flatfox.ch
    DESCRIPTION:Address: Schreinerstrasse 64\, 8004 Zürich\nContact person: B
     ernhard Mäder\nWhen: Sun\, 05/26/2019\, 5 p.m.\nAttendees: Max Muster - 2
     738492379847
    LOCATION:Schreinerstrasse 64\, 8004 Zürich
    ORGANIZER;CN=flatfox:MAILTO:<no_reply>@flatfox.ch
    PRIORITY:5
    STATUS:CONFIRMED
    BEGIN:VALARM
    ACTION:DISPLAY
    DESCRIPTION:Viewing at Schreinerstrasse 64\, 8004 Zürich
    TRIGGER:-PT30M
    END:VALARM
    END:VEVENT
    END:VCALENDAR
    

    The resulting payload (as received by the email client, after the sendgrid roundtrip) is as follows:

    --cc91f1040f2ddb86e28e23abd2298e8686508c1291386a1d824cb54aebce
    Content-Disposition: attachment; filename="termin.ics" Content-Transfer-Encoding: base64 Content-Type: text/calendar; name=termin.ics; charset=iso-8859-1
    QkVHSU46VkNBTEVOREFSDQpWRVJTSU9OOjIuMA0KUFJPRElEOi0vL2ZsYXRmb3gvL2ZsYXRmb3gu
    Y2gvLw0KTUVUSE9EOlJFUVVFU1QNCkJFR0lOOlZFVkVOVA0KU1VNTUFSWTpCZXNpY2h0aWd1bmcg
    ZvxyIFNjaHJlaW5lcnN0cmFzc2UgNjRcLCA4MDA0IFr8cmljaA0KRFRTVEFSVDtWQUxVRT1EQVRF
    LVRJTUU6MjAxOTA1MjZUMTUwMDAwWg0KRFRFTkQ7VkFMVUU9REFURS1USU1FOjIwMTkwNTI2VDE1
    MzAwMFoNCkRUU1RBTVA7VkFMVUU9REFURS1USU1FOjIwMTkwNTIzVDEyMzUzNFoNClVJRDo2Mzhi
    YjBjYS1mMjhhLTQ4YWItYWVkOS04ODYxYmY1ZTg3NGQuMTY2OTg2QGZsYXRmb3guY2gNClNFUVVF
    TkNFOjENCkFUVEVOREVFO0NOPSJNYXggTXVzdGVyIjtDVVRZUEU9SU5ESVZJRFVBTDtQQVJUU1RB
    VD1BQ0NFUFRFRDtST0xFPVJFUS1QQVJUDQogSUNJUEFOVDtSU1ZQPUZBTFNFO1gtTlVNLUdVRVNU
    Uz0wOk1BSUxUTzpiZXJuaGFyZC5tYWVkZXJAb3V0bG9vay5jb20NCkRFU0NSSVBUSU9OOkFkcmVz
    c2U6IFNjaHJlaW5lcnN0cmFzc2UgNjRcLCA4MDA0IFr8cmljaFxuS29udGFrdHBlcnNvbjogQmUN
    CiBybmhhcmQgTeRkZXJcblplaXQ6IFNvXCwgMjYuMDUuMjAxOVwsIDE3OjAwDQpMT0NBVElPTjpT
    Y2hyZWluZXJzdHJhc3NlIDY0XCwgODAwNCBa/HJpY2gNCk9SR0FOSVpFUjtDTj1mbGF0Zm94Ok1B
    SUxUTzpjYWxlbmRhckBmbGF0Zm94LmNoDQpQUklPUklUWTo1DQpTVEFUVVM6Q09ORklSTUVEDQpC
    RUdJTjpWQUxBUk0NCkFDVElPTjpESVNQTEFZDQpERVNDUklQVElPTjpCZXNpY2h0aWd1bmcgZvxy
    IFNjaHJlaW5lcnN0cmFzc2UgNjRcLCA4MDA0IFr8cmljaA0KVFJJR0dFUjotUFQzME0NCkVORDpW
    QUxBUk0NCkVORDpWRVZFTlQNCkVORDpWQ0FMRU5EQVINCg==
    --cc91f1040f2ddb86e28e23abd2298e8686508c1291386a1d824cb54aebce--
    

    The problem with this:

    • The payload is encoded with UTF-8, then converted to base64
    • The charset states iso-8859-1
    • Some mail client (outlook.com in particular) will now use the charset to decode the payload, which renders some characters wrongly. This is per spec, where the ICS's encoding may be deduced from the container's.

    So, I'd like the charset to be set to utf-8.

    Also interesting, but not really important: gmail, thunderbird and a few other clients will (incorrectly) use UTF-8, as this is the default encoding for icalendar files.

    • Any other relevant code and settings (e.g., for problems sending, your code that sends the message) None
    esp:SendGrid docs blocked 
    opened by nuschk 15
  • Missing or invalid basic auth in Anymail Mailgun webhook

    Missing or invalid basic auth in Anymail Mailgun webhook

    Thank you for maintaining Anymail, it is really great so far.

    I am trying to receive a webhook from Mailgun but I get an error.

    "Missing or invalid basic auth in Anymail Mailgun webhook"
    

    Anymail is configured correctly, and I have been sending email through Mailgun for about a week.

    ANYMAIL = {
        "MAILGUN_API_KEY": Env.value("MAILGUN_API_KEY"),
        "MAILGUN_SENDER_DOMAIN": Env.value("MAILGUN_SENDER_DOMAIN"),
        "WEBHOOK_AUTHORIZATION": Env.value("ANYMAIL_WEBHOOK_AUTHORIZATION"),
    }
    

    Today I added the "WEBHOOK_AUTHORIZATION" setting. Currently I am testing this feature on our dev environment. Therefore, the Mailgun sender domain is my Mailgun sandbox domain.

    I set the Mailgun "Unsubscribes" web hook to the url defined in the Anymail documentation.

    https://secret1:[email protected]/anymail/mailgun/tracking/
    

    And in my urls.py

    url(
        r'^anymail/',
        include('anymail.urls')
    ),
    

    When I receive an email and click the unsubscribe link, a POST is made to my server, but I get the error listed above.

    For what it's worth, I am hosting my site on Webfaction using Apache.

    I found a nearly identical issue on Stackoverflow, but no answer provided. https://stackoverflow.com/questions/38620608/django-anymail-mailgun-webhook-no-http-authorization-in-meta

    opened by pymarco 15
  • mandrill webhook: incorrect signature with auth

    mandrill webhook: incorrect signature with auth

    dear, Im getting Mandrill webhook called with incorrect signature error with a Bad Request response towards mandrill.

    Sentry logs say about the err location:

    filename	
    'base.py'
    lineno	
    216
    pathname	
    '/home/onlinegv/eggs/Django-1.9.9-py2.7.egg/django/core/handlers/base.py'
    

    I triple checked my webhook and api key. my total settings look like this:

            ANYMAIL =  {
                'MANDRILL_API_KEY': get_config_or_none(
                    config,'Email', 'mandrill_api_key', 'SOMEKEY-A'),
                'WEBHOOK_AUTHORIZATION':'SOMEAUTH:SOMEPW',
                'MANDRILL_WEBHOOK_KEY': get_config_or_none(
                    config, 'Email', 'mandrill_webhook_key', 'SOMEKEY'),
            }
    

    what else should I check to investigate the failure?

    bug esp:Mandrill 
    opened by patroqueeet 15
  • Inbound mail

    Inbound mail

    I'm currently evaluating django-anymail (with mailgun) which I will be using inbound mail with and see on your roadmap that you intend to add inbound mail support. Did you have a structure/plan in mind for doing this, before I do a quick specific implementation similar to the mailgun docs, which probably won't be suitable for django-anymail?

    feature/enhancement 
    opened by yunti 14
  • Mailgun Template Support

    Mailgun Template Support

    The docs claim that

    Mailgun does not offer ESP stored templates, so Anymail’s template_id message attribute is not supported with the Mailgun backend.

    but that does not appear to be true: https://documentation.mailgun.com/en/latest/api-templates.html

    Am I mistaking either Anymail's or Mailgun's docs?

    feature/enhancement esp:Mailgun 
    opened by anstosa 12
  • SendGrid smtp-id not always matching anymail_status

    SendGrid smtp-id not always matching anymail_status

    ESP: SendGrid django-anymail: 2.2 Python: 2.7 Django: 1.11.10

    Just after we make the msg = AnymailMessage(**kwargs) call we store the data from msg.anymail_status in our database for tracking. The issue we're seeing is that the SendGrid webhook will often times return POST data with a message_id and esp_event['smtp-id] that do not match the values Anymail generated for us.

    As an example: We send a message and receive an smtp-id of <[email protected]> in the msg.anymail_status. When the webhook communicates updates to us we find that the message_id for the same message is <[email protected]> which means that we are unable to identify which message this belongs to.

    Here's the code that calls AnymailMessage:

    text_message = render_to_string(templates['text'], context)
    html_message = render_to_string(templates['html'], context)
    msg = AnymailMessage(
        subject=templates['subject'],
        body=text_message,
        to=[user.email],
    )
    msg.attach_alternative(html_message, "text/html")
    msg.send()
    
    # store the anymail status data to our database for tracking via the webhook
    Email().create_from_anymail(msg.anymail_status, Email.INVITATION)
    

    The Email() model holds the create_from_anymail(anymail_status, event) method where event is an optional custom tracker for the event triggering the email send (unrelated to anymail):

    @classmethod
    def create_from_anymail(cls, anymail_status, event=None):
        for recipient in anymail_status.recipients:
            kwargs = {
                'to_email': recipient,
                'status': anymail_status.recipients[recipient].status,
                'message_id': anymail_status.recipients[recipient].message_id,
                'response': anymail_status.esp_response
            }
    
            if event:
                kwargs['event'] = event
    
            email = Email(**kwargs)
            email.save()
    

    From what I can gather from the SendGrid webhook documentation the smtp-id should be returned for every webhook POST and is a unique ID attached to the message by the originating system.

    I've also contacted SendGrid support but wanted to present the issue here in case anyone has seen something similar and may have ideas on how to get a consistent identifier from our system into SendGrid.

    esp:SendGrid 
    opened by joshkersey 11
  • from_email surrounded by quotation marks when it contains special characters with Mailgun

    from_email surrounded by quotation marks when it contains special characters with Mailgun

    HI! We have recently changed our ESP from Sparkpost to Mailgun. Using this librairy has saved us a lot of time. We thank you for that!

    Everything works well except for one annoying detail: The from email gets surrounded by quotes when containing a special character like 'é' or 'è'. This was not an issue when using Sparkpost.

    Here's an example of what I mean:

    def send_welcome_email(from_email, recipients):
        html_content = get_template("welcome.html")
        message = EmailMultiAlternatives(
            subject="Welcome to MyApp",
            body="Welcome!",
            from_email=from_email,
            to=recipients,
        )
        message.attach_alternative(html_content, "text/html")
        message.send()
    
    

    Now if we use this method like this:

    send_welcome_email("Felix (via MyApp) <[email protected]>", ["[email protected]"]) 
    

    I get the expected result (In Gmail, when I click "Show original" I can see the following)

    From: "Felix (via MyApp)" <[email protected]>

    But, if I use the method like this:

    send_welcome_email("Félix (via MyApp) <[email protected]>", ["[email protected]"])  # Notice the 'é' instead of the 'e'
    

    I get this result:

    From: "\"Félix (via MyApp)\"" <[email protected]>

    When we were using Sparkpost, this was not a problem (we got the expected result with the 'é'). It looks quite ugly and unprofessional in the recipients' mailboxes, and since our application is aimed at french users and many french names have special characters like 'é' or 'è' in them, this is a big problem for us.

    Hope someone can help :) Thank you!


    • Anymail version: 8.4.0
    • ESP: Mailgun (previously Sparkpost)
    • Django 3.2, python 3.9.6
    esp:Mailgun not our bug 
    opened by Flexonze 10
  • AnymailRequestsAPIError with Mailgun API response 200

    AnymailRequestsAPIError with Mailgun API response 200 "Mailgun Magnificent API"

    Reporting an error? It's helpful to know:

    • Anymail version: 5.0
    • ESP : Mailgun
    • Versions of Django 2.1.7
    • Exact error message and/or stack trace

    AnymailRequestsAPIError at /emails/ Invalid JSON in Mailgun API response Sending a message to [email protected] from dev.te[email protected] Mailgun API response 200: OK Mailgun Magnificent API

    Exception Value: Invalid JSON in Mailgun API response Sending a message to [email protected] from dev.te[email protected] Mailgun API response 200: OK Mailgun Magnificent API

    Anymail is throwing an exception, but mailgun is sending 200

    bug esp:Mailgun 
    opened by chiragchamoli 10
  • Mailersend ESP support

    Mailersend ESP support

    Hi,

    We really appreciate guys if you could integrate mailersend ESP (https://mailersend.com), and Sendpulse ESP (https://sendpulse.com/)

    it's a reaaaaly serious player in the ESP space, with 12,000 to 15,000 emails/month Send for free

    Thank you

    opened by anugrahsoft 0
  • Reduced DEBUG_API_REQUESTS

    Reduced DEBUG_API_REQUESTS

    Just a suggestion: would it be possible to add a "reduced" DEBUG_API_REQUESTS implementation to log only basic information about the requests and responses (eg. status code, possibly errors in the response; a subset of fields in the request) to allow use outside dev environments? I'm asking because we had an impossible to track intermittent problem with some notifications (ESP is Postmark) - all our logs confirmed that the email was sent, but nothing was apparently received by Postmark, and Anymail showed no error.

    future design 
    opened by pgcd 2
  • Utilize pre-commit, black, isort and doc8

    Utilize pre-commit, black, isort and doc8

    It will be easier to contribute if the style preferences of the project were enforced automatically. pre-commit is a tool that supports this. I've set it up to apply black, isort and doc8 to standardize the coding style.

    Obviously, this is a large change and I don't have a ton of involvement with the project historically. However, these tools have made my life easier on other projects, especially those that I am reviewing pull requests for.

    Edit: If this is too much to take on, that's understandable and I won't be offended.

    opened by tim-schilling 7
  • [Feature Request] Add SMTP Backend with signal support

    [Feature Request] Add SMTP Backend with signal support

    It was recommended in the docs to use the default Django EmailBackend for SMTP. However, by doing this, we are losing the advantages of the pre- and post-send signals.

    The use-case that we have right now is we are using a mail catcher on the local setup (which is SMTP) and then switches our backend to Mailjet on production.

    The issue is that we had to write our own SMTP backend to get the same behavior as one of the Anymail-supported backends' pre- and post-send.

    Anymail has the test and console backends but is missing the SMTP backend.

    opened by roniemartinez 3
  • Amazon SES v2

    Amazon SES v2

    Hi, this is just a heads-up. I've noticed that AWS released SESV2 API which is a bit different from V1 implemented in anymail.

    There is a change that "Raw" email method is changed to parameter of SendEmail

    See affected methods:

    V1 SendRawEmail SendBulkTemplatedEmail V2 SendBulkEmail v2 SendEmail v2

    This also results in IAM permissions changes

    V1

    "ses:SendRawEmail",
    "ses:SendBulkTemplatedEmail",
    

    V2

    "ses:SendEmail",
    "ses:SendBulkEmail"
    

    PS. Feel free to close this issue if you do not plan to update because it may be unlikely that AWS is going to deprecate standard SES API any time soon.

    feature/enhancement esp:Amazon SES 
    opened by 1oglop1 5
Releases(v9.0)
  • v8.0(Sep 11, 2020)

  • v7.1.0(Jun 22, 2020)

  • v4.0(Aug 19, 2018)

  • v3.0(May 30, 2018)

    Changes

    • Breaking change: Python 3.3 is no longer supported (see #99).
    • Mailjet: Fix tracking webhooks to work correctly when Mailjet "group events" option is disabled (see #106).
    • SendGrid: Fix a problem where Anymail's status tracking webhooks didn't always receive the same event.message_id as the sent message.anymail_status.message_id, due to unpredictable behavior by SendGrid's API. Anymail now generates a UUID for each sent message and attaches it as a SendGrid custom arg named anymail_id. For most users, this change should be transparent. But it could be a breaking change if you are relying on a specific message_id format, or relying on message_id matching the Message-ID mail header or SendGrid's "smtp-id" event field. (More details in the docs; also see #108.) Thanks to @joshkersey for the report and the fix.
    • Support Django 2.1 prerelease.

    Deprecations

    • This will be the last Anymail release to support Django 1.8, 1.9, and 1.10 (see #110).
    • This will be the last Anymail release to support the legacy SendGrid v2 EmailBackend (see #111). (SendGrid's newer v3 API has been the default since Anymail v0.8.)
    • Anymail v3.x will receive security updates and fixes for any breaking ESP API changes through at least April, 2019.
    • If these deprecations affect you and you cannot upgrade, set your requirements to django-anymail~=3.0 (a "compatible release" specifier, equivalent to >=3.0,==3.*).
    Source code(tar.gz)
    Source code(zip)
  • v2.2(Apr 16, 2018)

  • v2.1(Apr 11, 2018)

    NOTE: v2.1 accidentally introduced a breaking change: enabling Anymail webhooks with include('anymail.urls') causes an error if boto3 is not installed, even if you aren't using Amazon SES. This is fixed in v2.2.

    New features

    • Amazon SES: Newly-supported ESP (docs).
    • SparkPost: Add SPARKPOST_API_URL setting to support SparkPost EU and SparkPost Enterprise (docs).

    Other changes

    • Inbound: Fix several issues with inbound messages, particularly around non-ASCII headers and body content. Add workarounds for some limitations in older Python email packages.
    • Postmark: Update for Postmark "modular webhooks." This should not impact client code. (Also, older versions of Anymail will still work correctly with Postmark's webhook changes.)
    • Use tox to manage Anymail test environments (see contributor docs).

    Notice

    This will be the last Anymail release to support Python 3.3. See #99 for more information.

    Source code(tar.gz)
    Source code(zip)
  • v2.0(Mar 8, 2018)

    Important updates

    • Breaking change: Drop support for deprecated WEBHOOK_AUTHORIZATION setting. If you are using webhooks and still have this Anymail setting, you must rename it to WEBHOOK_SECRET. See the v1.4 release notes.

    New features

    • SendinBlue: Add new ESP (docs). Thanks to @RignonNoel for the implementation.
    • Add EmailMessage envelope_sender attribute, which can adjust the message's Return-Path if supported by your ESP (docs).
    • Add universal wheel to PyPI releases for faster installation.

    Other changes

    • Handle Reply-To, From, and To in EmailMessage extra_headers the same as Django's SMTP EmailBackend if supported by your ESP, otherwise raise an unsupported feature error. Fixes the SparkPost backend to be consistent with other backends if both headers["Reply-To"] and reply_to are set on the same message. If you are setting a message's headers["From"] or headers["To"] (neither is common), the new behavior is likely a breaking change. See docs and #91.
    • Treat EmailMessage extra_headers keys as case-insensitive in all backends, for consistency with each other (and email specs). If you are specifying duplicate headers whose names differ only in case, this may be a breaking change. See docs.
    • Update setup.py metadata, clean up implementation. (Hadn't really been touched since original Djrill version.)
    • Prep for Python 3.7.
    Source code(tar.gz)
    Source code(zip)
  • v1.4(Feb 8, 2018)

    Security fix

    This fixes a low severity security issue affecting Anymail v0.2–v1.3. (CVE-2018-1000089)

    Django error reporting includes the value of your Anymail WEBHOOK_AUTHORIZATION setting. In a properly-configured deployment, this should not be cause for concern. But if you have somehow exposed your Django error reports (e.g., by mis-deploying with DEBUG=True or by sending error reports through insecure channels), anyone who gains access to those reports could discover your webhook shared secret. An attacker could use this to post fabricated or malicious Anymail tracking/inbound events to your app, if you are using those Anymail features.

    The fix renames Anymail's webhook shared secret setting so that Django's error reporting mechanism will sanitize it.

    If you are using Anymail's event tracking and/or inbound webhooks, you should upgrade to this release and change "WEBHOOK_AUTHORIZATION" to "WEBHOOK_SECRET" in the ANYMAIL section of your settings.py. You may also want to rotate the shared secret value, particularly if you have ever exposed your Django error reports to untrusted individuals.

    If you are only using Anymail's EmailBackends for sending email and have not set up Anymail's webhooks, this issue does not affect you.

    The old WEBHOOK_AUTHORIZATION setting is still allowed in this release, but will issue a system-check warning when running most Django management commands. It will be removed completely in a near-future release, as a breaking change.

    Thanks to Charlie DeTar (@yourcelf) for responsibly reporting this security issue through private channels.

    Source code(tar.gz)
    Source code(zip)
  • v1.3(Feb 2, 2018)

    Security fix

    v1.3 includes the v1.2.1 security fix released at the same time. Please review the v1.2.1 release notes, below, if you are using Anymail's tracking webhooks.

    New features

    • Inbound handling: Add normalized inbound message event, signal, and webhooks for all supported ESPs. (See new Receiving mail docs.) This hasn't been through much real-world testing yet; bug reports and feedback are very welcome.
    • API network timeouts: For Requests-based backends (all but SparkPost), use a default timeout of 30 seconds for all ESP API calls, to avoid stalling forever on a bad connection. Add a REQUESTS_TIMEOUT Anymail setting to override. (See #80.)
    • Test backend improvements: Generate unique tracking message_id when using the test backend; add console backend for use in development. (See #85.)
    Source code(tar.gz)
    Source code(zip)
  • v1.2.1(Feb 2, 2018)

    Security fix

    This release fixes a moderate severity security issue affecting Anymail v0.2–v1.2: Prevent timing attack on WEBHOOK_AUTHORIZATION secret (CVE-2018-6596)

    If you are using Anymail's tracking webhooks, you should upgrade to this release, and you may want to rotate to a new WEBHOOK_AUTHORIZATION shared secret (see docs). You should definitely change your webhook auth if your logs indicate attempted exploit.

    (If you are only sending email using an Anymail EmailBackend, and have not set up Anymail's event tracking webhooks, this issue does not affect you.)

    More information

    Anymail's webhook validation was vulnerable to a timing attack. A remote attacker could use this to obtain your WEBHOOK_AUTHORIZATION shared secret, potentially allowing them to post fabricated or malicious email tracking events to your app.

    There have not been any reports of attempted exploit. (The vulnerability was discovered through code review.) Attempts would be visible in HTTP logs as a very large number of 400 responses on Anymail's webhook urls (by default "/anymail/esp_name/tracking/"), and in Python error monitoring as a very large number of AnymailWebhookValidationFailure exceptions.

    Source code(tar.gz)
    Source code(zip)
  • v1.2(Nov 2, 2017)

  • v1.1(Oct 28, 2017)

    Bug fixes

    • Mailgun: Support metadata in opened/clicked/unsubscribed tracking webhooks, and fix potential problems if metadata keys collided with Mailgun event parameter names. (See #76, #77)

    Other changes

    • Internal: Rework Anymail's ParsedEmail class and rename to EmailAddress to align it with similar functionality in the Python 3.6 email package, in preparation for future inbound support. ParsedEmail was not documented for use outside Anymail's internals (so this change does not bump the semver major version), but if you were using it in an undocumented way you will need to update your code.
    Source code(tar.gz)
    Source code(zip)
A small system for writing via email.

A small system for writing via email.

0 Nov 24, 2021
An offline Phishing Email Analyzer.

An offline Phishing Email Analyzer.

Kamran Saifullah (Frog Man) 11 Oct 19, 2022
Generate Email, Register for anything, Get the OTP/Link

OTE : One Time Email Introduction ote is a command line utility that generates temporary email address and automatically extracts OTPs or confirmation

Somdev Sangwan 457 Jan 03, 2023
Send email notification when receiving Facebook message.

Send email notification when receiving Facebook message.

Radon Rosborough 4 May 08, 2022
You take an email and password from the combo list file and check it on mail.com

Brute-Force-mail tool information: Combo Type: email:pass Domains: All domains of the site Url: https://www.mail.com Api: ☑️ Proxy: No ☑️ The correct

6 Jun 05, 2022
Suplantar mails de empresas como google, facebook, github, etc...

Suplantar mails de empresas como google, facebook, github, etc...

piter 3 Feb 05, 2022
ghotok mail - lets you find available contact email addresses from target website

ghotok-mail ghotok mail - lets you find available contact email addresses from target website git clone https://github.com/josifkhan/ghotok-mail cd gh

Md Josif Khan 3 Mar 14, 2022
This is a bot that interacts with you over voice and sends mail.Uses speech_recognition,pyttsx3 and smtplib

AutoMail This is a bot that interacts with you over voice and sends mail Before you run the bot , go to mail.py and put your respective email address

Aditya Subrahmanya Bhat 2 Nov 04, 2022
A Discord Mod Mail bot made in python

Fish-Mail The mod mail bot for Fish Hosting Note: You are not allowed to remove the names in the credit command Note: If you want any ideas/commands a

28 Aug 30, 2022
Using this repository you can send mails to multiple recipients.Was created in support of Ukraine, to turn society`s attention to war.

mails-in-support-of-UA Using this repository you can send mails to multiple recipients.Was created in support of Ukraine, to turn society`s attention

Oleksii Budzinskiy 2 Mar 04, 2022
📧 CLI to deduplicate mails from mail boxes.

Mail Deduplicate Command-line tool to deduplicate mails from a set of boxes. Stable release: Development: Features Duplicate detection based on cherry

Kevin Deldycke 134 Dec 14, 2022
A python script that helps you understand why your E-Mail ended up in Spam

decode-spam-headers.py Whether you are trying to understand why a specific e-mail ended up in SPAM/Junk for your daily Administrative duties or for yo

Mariusz Banach 316 Jan 05, 2023
Read/sync your IMAP mailboxes (python2)

Upstream status (master branch): Upstream status (next branch): Financial contributors: Links: Official github code repository: offlineimap Website: w

OfflineIMAP 1.7k Dec 29, 2022
automatic mails sender with attachments

أزعجني لين تدربني Automatic mails sender with attachments. Note: You need to have gmail account & and you need to turn on "Less secure app access" set

6 Dec 30, 2022
A light-weight, modular, message representation and mail delivery framework for Python.

Marrow Mailer A highly efficient and modular mail delivery framework for Python 2.6+ and 3.2+, formerly called TurboMail. © 2006-2019, Alice Bevan-McG

Marrow Open Source Collective 255 Dec 28, 2022
A Django app that allows you to send email asynchronously in Django. Supports HTML email, database backed templates and logging.

Django Post Office Django Post Office is a simple app to send and manage your emails in Django. Some awesome features are: Allows you to send email as

User Inspired 856 Dec 25, 2022
Will iterate through a list of emails on an attached csv file and email all of them a message of your choice

Email_Bot Will iterate through a list of emails on an attached csv file and email all of them a message of your choice. Before using, make sure you al

J. Brandon Walker 1 Nov 30, 2021
A SMTP server for use as a pytest fixture that implements encryption and authentication.

SMTPDFix: Test email, locally A simple SMTP server based on aiosmtpd for use as a fixture with pytest that supports encryption and authentication. All

James Warne 11 Sep 03, 2022
A script based on an article I wrote on decluttering emails.

Decluttering_Email A script based on an article I wrote on decluttering emails. What does this program do? This program is a python script that sends

Ogheneyoma Obomate Okobiah 6 Oct 21, 2021
Spam-bot - Simple email-spammer discord bot

📝 Functional [ ✔️ ] Premium system via .json [ ✔️ ] Spammer [ ✔️ ] Validater [ ✔️ ] Discord bot ❓ How to launch ➡️ 1) Make discord bot ➡️ 2) Paste to

1 Feb 18, 2022