Red-mail - Advanced email sending library for Python

Overview

Red Mail

Next generation email sender


Pypi version build codecov Documentation Status PyPI pyversions

What is it?

Red Mail is an advanced email sender library. It makes sending emails trivial and has a lot of advanced features such as:

  • Attachments
  • Templating (via Jinja)
  • Prettified tables
  • Embedded images

See more from the documentations or see release from PyPI.

Why Red Mail?

Sending emails should not be this complicated:

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

msg = MIMEMultipart('alternative')
msg['Subject'] = 'An example email'
msg['From'] = '[email protected]'
msg['To'] = '[email protected]'

part1 = MIMEText("Hello!", 'plain')
part2 = MIMEText("<h1>Hello!</h1>", 'html')

msg.attach(part1)
msg.attach(part2)

# Send the message via our own SMTP server.
s = smtplib.SMTP('localhost', port=0)
s.send_message(msg)
s.quit()

With Red Mail, it's simple as this:

from redmail import EmailSender

email = EmailSender(host="localhost", port=0)

email.send(
    subject="An example email",
    receivers=['[email protected]'],
    text="Hello!",
    html="<h1>Hello!</h1>"
)

You can also do more advanced things easily with it:

from redmail import EmailSender

email = EmailSender(host="localhost", port=0)

email.send(
    subject="An example email",
    sender="[email protected]",
    receivers=['[email protected]'],
    html="""<h1>Hello {{ friend }}!</h1>
        <p>Have you seen this thing</p>
        {{ awesome_image }}
        <p>Or this:</p>
        {{ pretty_table }}
        <p>Or this plot:</p>
        {{ a_plot }}
        <p>Kind regards, {{ sender.full_name }}</p>
    """,

    # Content that is embed to the body
    body_params={'friend': 'Jack'},
    body_images={
        'awesome_image': 'path/to/image.png',
        'a_plot': plt.Figure(...)
    },
    body_tables={'pretty_table': pd.DataFrame(...)},

    # Attachments of the email
    attachments={
        'some_data.csv': pd.DataFrame(...),
        'file_content.html': '<h1>This is an attachment</h1>',
        'a_file.txt': pathlib.Path('path/to/file.txt')
    }
)

Author

Comments
  • Different sending email address or alias when sending via gmail

    Different sending email address or alias when sending via gmail

    Is your feature request related to a problem? Please describe. No.

    Describe the solution you'd like Allow for different sending email address or alias when sending via gmail – i.e. from redmail import gmail.

    Describe alternatives you've considered None.

    Additional context n/a

    documentation enhancement 
    opened by LucSpan 5
  • Fix embedded image cid for named senders with a 'from' address like 'Sender <noreply@sender.com>'

    Fix embedded image cid for named senders with a 'from' address like 'Sender '

    I was struggeling with embedding an image in an html mail body. The picture was attached however it didn't show up in Outlook.

    The issue was caused by the sender address which was something like 'AnyFancyName [email protected]'. To be precise the issue is caused by the '>' at the end of the string which survives with your current split logic and causes the cid to have two '>' characters at the end.

    I would suggest to use parseaddr function from email.utils to get the raw email address from the msg['from'] field.

    opened by StefanVietze 3
  • setup.py: add MIT license to classifiers

    setup.py: add MIT license to classifiers

    The project contains an MIT license in the LICENSE file, but this is not reflected in the package classifiers.

    I'd like to consider using red-mail in a project, but the automation requires the license to be listed in the classifiers. Please consider merging.

    opened by rveachkc 3
  • fix: support non-PNG embedded images as dict

    fix: support non-PNG embedded images as dict

    Fix to support also other than just PNG formats passed as dict, like:

    email.send(
        subject="Example",
        receivers=[...],
        html="<h1>Example</h1> {{ my_image }}",
        body_images={
            'my_image': {
                'content': b'<image as bytes>',
                'maintype': 'image',
                'subtype': 'jpeg',
            }
        }
    )
    
    bug 
    opened by Miksus 3
  • Change from

    Change from "redengine" to "redmail" for import line

    A small correction - the docs refer to importing "redengine" in the Getting Started page rather than "redmail". Unless I've misunderstood something, I think it should be importing "redmail" based on the further code examples on the page.

    opened by kimvanwyk 3
  • BUG: Email structure

    BUG: Email structure

    This PR changes the structure of the email (in terms of content-types). It should not affect the content (attachments, inline images etc.) but it should fix rendering issues with different email providers.

    If only text

    • multipart/mixed
      • text/plain

    If only HTML

    • multipart/mixed
      • multipart/alternative
        • text/html

    If only attachment

    • multipart/mixed
      • application/octet-stream

    If text and HTML

    • multipart/mixed
      • multipart/alternative
        • text/plain
        • text/html

    If text and HTML and embedded image, and attachment

    • multipart/mixed
      • multipart/alternative
        • text/plain
        • multipart/related
          • text/html
          • image/jpg
      • application/octet-stream
    bug MIME 
    opened by Miksus 2
  • BUG: E-Mails aren't being sent, no error messages etc

    BUG: E-Mails aren't being sent, no error messages etc

    email = EmailSender(
            host=config.smtp_server,
            port=config.smtp_port,
            user_name=config.smtp_user,
            password=config.smtp_pass
    )
    email.send(
        subject="My Subject",
        sender=config.smtp_user,
        receivers=["[email protected]"],
        text="Test"
    )
    

    Is not doing anything, emai is not receiving anything and there are also no messages. The only Error I get after like 3-5 minutes is the following:

    raise SMTPServerDisconnected("Connection unexpectedly closed")
    smtplib.SMTPServerDisconnected: Connection unexpectedly closed
    

    Can anyone validate that the latest version does indeed work with a simple example as above.

    The same credentials work with the standard python smtp code with no issues eg.

    server = smtplib.SMTP_SSL(config.smtp_server, config.smtp_port, context=ssl.create_default_context())
    server.login(config.smtp_user, config.smtp_pass)
    message = MIMEMultipart("alternative")
    message["Subject"] = "Subject"
    message["From"] = config.smtp_user
    message["To"] = recipient
    
    bug 
    opened by tarik56 2
  • Base64 img

    Base64 img

    Hello, first of all thank you for this insane package.

    I would like to add an image in base64 format in a <img src="{{ my_image_b64 }}" class="" />using body_images = {}

    Is this possible?

    If yes can you show me an example, my image is a string in base64 format (data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAA .... )

    Thanks a lot

    opened by ghost 2
  • test: fix some Python 3.6 test failures

    test: fix some Python 3.6 test failures

    This PR only affects tests as only some tests were broken in Python 3.6 (but no actual code was). This PR is the result of fixing a typo in CI build that caused the build test to run only on Python 3.8.

    opened by Miksus 1
  • DOCS: disable jinja

    DOCS: disable jinja

    I want to send a complex email: css and sh*t. I don't need jinja for this email, but I get errors when sending the email, since the css syntax tricks the jinja parser. Could fix it, double curly braces everywhere, but: Is there a way to send the html without jinja parsing? Regards

    Traceback (most recent call last):
      File "./test_embed_redmail.py", line 136, in <module>
        email.send(
      File "/usr/local/lib/python3.8/dist-packages/redmail/email/sender.py", line 260, in send
        msg = self.get_message(
      File "/usr/local/lib/python3.8/dist-packages/redmail/email/sender.py", line 334, in get_message
        body.attach(
      File "/usr/local/lib/python3.8/dist-packages/redmail/email/body.py", line 113, in attach
        html, cids = self.render(
      File "/usr/local/lib/python3.8/dist-packages/redmail/email/body.py", line 173, in render
        html = super().render(html, tables=tables, jinja_params=jinja_params)
      File "/usr/local/lib/python3.8/dist-packages/redmail/email/body.py", line 76, in render
        return self.render_body(cont, jinja_params={**tables, **jinja_params})
      File "/usr/local/lib/python3.8/dist-packages/redmail/email/body.py", line 51, in render_body
        template = Environment().from_string(body)
      File "/home/user/.local/lib/python3.8/site-packages/jinja2/environment.py", line 1092, in from_string
        return cls.from_code(self, self.compile(source), gs, None)
      File "/home/user/.local/lib/python3.8/site-packages/jinja2/environment.py", line 757, in compile
        self.handle_exception(source=source_hint)
      File "/home/user/.local/lib/python3.8/site-packages/jinja2/environment.py", line 925, in handle_exception
        raise rewrite_traceback_stack(source=source)
      File "<unknown>", line 11, in template
    jinja2.exceptions.TemplateSyntaxError: expected token 'end of print statement', got ':'
    
    documentation 
    opened by pablo-angulo 1
  • BUG: Emails with templates do not attach files correctly

    BUG: Emails with templates do not attach files correctly

    First of all, thank you for this life-saving library: Easy templating has been a total game-changer.

    Describe the bug When using Jinja templates, attached files are not correctly attached to the email, as the message Content-Type is set to multipart/alternative instead of multipart/mixed.

    Attachments are treated by mail clients as embedded content and thus not shown or recognized as attachments.

    To Reproduce Steps to reproduce the behavior:

    1.- Create a simple snippet that includes both a template and an attachment (in any form):

    redmail.send(
                    subject='[%s] Email data for %s' % (str(instance),str(mail_id)),
                    receivers=[str(email_address)],
                    html_template='jinja_template.html',
                    attachments=str(os.path.join(temp_path, str(attachment_filename))),
                    body_params={'json_data': json_data,},
                    body_images={
                        'logo': '/tmp/ogo.png',
                    },
                )
    

    Expected behavior The mail is shown in the email client with the attachment.

    Instead, the attachment is in the mail's source code but not available to download from the client.

    Email provider:

    • Email service: private postfix
    • Application to view the email: Thunderbird, Gmail Client

    Environment (please complete the following information if relevant):

    • OS: Linux
    • Python version: 3.8
    • Red Mail version: 0.3.1

    Additional context

    It is possible to fix this issue temporalily by modifying the 'attach' method from attachment.py to always set the message as mixed:

    def attach(self, msg:EmailMessage):
            if msg.get_content_type() == "text/plain":
                # We need to change the content type
                # This occurs if no body is defined or only text is defined
                # The content type is therefore changed to multipart/mixed
                # See issue #23
                msg.make_mixed()
            else:
                try:
                    msg.make_mixed()
                except Exception:
                    pass
            for part in self._get_parts():
                msg.attach(part)
    
    bug 
    opened by Godlance 1
  • BUG: Date header missing

    BUG: Date header missing

    Hello,

    I stumbled upon an issue using my ISP's SMTP server (Orange, a french ISP). By default, they don't add the email's "Date" header if it's missing, and it's considered a required field by their servers.

    Reproduction steps Create an orange email address at : https://login.orange.fr/signup/identity Send an email using Redmail with the ISP's default SMTP server : smtp.orange.fr (port 587)

    Error Every time, I get this kind of error email :

    image

    Additional info Redmail version : 0.4.2 Python version : 3.8

    I can PM the error email if needed.

    I can send emails fine through their web client and using python's "email" package if I set the date using this :

    [...]
    from email.mime.multipart import MIMEMultipart
    msg = MIMEMultipart('alternative')
    msg['Date'] = utils.formatdate(localtime=True)
    

    I believe the date field can be added in the "_create_body" function in "sender.py". Maybe add a boolean parameter to allow adding the date, set to false by default, just in case it breaks something for someone else ?

    I'm unsure if this should be a feature request or a bug, but since it's an error I can't get around using this library, I created a bug. If it needs to be a feature request, let me know.

    Thanks for any help !

    bug 
    opened by PierrePetit 0
  • Add support for styler pandas object

    Add support for styler pandas object

    See here :Styler object docs

    This PR uses premailer as a way to convert CSS styling into inline CSS styling for wider support on mail clients (