How to Send Emails in Flask
Tags: python, tutorial, webdev, programming
Published: 2022-04-11 14:09:47

Flask is a popular Python web framework and the preferred choice for many web developers. It’s often referred to as a microframework because of its limited capabilities and the general minimalist approach to the development in Python. As such, it also doesn’t offer a native solution for sending emails, but more than makes up for it with an excellent Flask-Mail extension.

In this article, we’ll explain how to configure and send emails with Flask-Mail.To get started, we’ll need to take care of a few brief installs, traditionally done with a pip. If you don’t have Flask installed yet - check out the full article [How to Send Emails in Flask](https://mailtrap.io/blog/flask-email-sending/) at [Mailtrap](http://mailtrap.io) blog.

## Sending emails in Flask

Email sending in Flask-Mail is handled by an instance of a Mail class.

`from flask import Flask
from flask_mail import Mail`

`app = Flask(app_name) # pick the name
mail = Mail(app)
`
We’ll need to set up a Message object, mapped by the URL rule (‘/’), and insert the base details of our message:

```
@app.route("/")
def index():
  msg = Message('Hello from the other side!', sender =   'alexandra@mailtrap.io', recipients = ['paul@mailtrap.io'])
  msg.body = "Hey Paul, sending you this email from my Flask app, lmk if it works"
  mail.send(msg)
  return "Message sent!"
```

All in all, the entire code will look like this:

```
from flask import Flask
from flask_mail import Mail

app = Flask(app_name)

app.config['MAIL_SERVER']='smtp.mailtrap.io'
app.config['MAIL_PORT'] = 2525
app.config['MAIL_USERNAME'] = '97e041d5e367c7'
app.config['MAIL_PASSWORD'] = 'cfaf5b99f8bafb'
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USE_SSL'] = False
mail = Mail(app)

@app.route("/")
def index():
  msg = Message('Hello from the other side!', sender =   'alexandra@mailtrap.io', recipients = ['paul@mailtrap.io'])
  msg.body = "Hey Paul, sending you this email from my Flask app, lmk if it works"
  mail.send(msg)
  return "Message sent!"

if __name__ == '__main__':
   app.run(debug = True)
```

Run it in Python Shell, open http://localhost:5000/, and check whether the email arrived in your inbox. It certainly arrived in ours!
 
**Customizing**

MAIL_DEFAULT_SENDER from the configuration is, by default, set to none and we skipped it in our setup. However, if you want to keep sending from the same address, it makes sense to specify it there. 
A good idea is to also specify the display name for a sender:

`msg = Message('Hello from the other side!', sender =  ("Alexandra from Mailtrap", 'peter@mailtrap.io')`

You can also specify a HTML version of the message. It can be sent along with a body message or without it.

`msg.body = "Hey Paul, sending you this email from my Flask app, lmk if it works"
msg.html = "<b>Hey Paul</b>, sending you this email from my <a href="https://google.com">Flask app</a>, lmk if it works"`

You may also add someone in cc and/or bcc, set a reply-to address, add extra headers, and so on. Here’s the full list of parameters available:

`flask-mail.Message(subject, recipients, body, html, sender, cc, bcc, reply-to, date, charset, extra_headers, mail_options, rcpt_options)`

**Adding an attachment**

Flask-Mail also provides an easy way to attach an attachment to our message. We need to load it with open_resource() method and then use a Python “with” statement to add a file to our email. 

`with app.open_resource("invoice.pdf") as fp:  
msg.attach("invoice.pdf", "application/pdf", fp.read()) `

Make sure you pick a proper [MIME Type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types) for each file and that each is uploaded to the same directory as your script.

**Sending bulk messages**

Most often, the Flask-Mail example above will be sufficient, but there are situations when you need to send dozens or even hundreds of emails for each request. Think about various cron jobs, for example.

For that, we can use a Python “with” statement. The connection to our email will be kept alive until all emails have been sent (at which point it will close automatically). If you wish to specify the maximum number of emails to be sent, use _MAIL_MAX_EMAILS_ from the configuration (by default, no limit is set).

```
with mail.connect() as conn:
    for user in users:
        message = '...'
        subject = "Hello from the other side!"
        msg = Message(recipients=[user.email],
                      body=message,
                      subject=subject)

        conn.send(msg)

```
**Other options**

Flask-Mail also provides many more options for you to quickly configure an email, add the headers, body, and a number of other parameters. It’s concise and very easy to grasp. 

Check the [official documentation](https://pythonhosted.org/Flask-Mail/#api) here to see them all.

## Sending emails asynchronously

An important aspect to consider when setting up emails is the possibility of sending them asynchronously. 

Let’s look at a typical situation. A user enters your site with the intention of sending you an email. They fill out a form, hit a ‘send’ button, and wait. 

In the background, a template is put together and an attempt to reach an ESP (email sending provider) is initiated. Most of the time, it responds within a few milliseconds and sends an email while the user is redirected to some “thank you” page.

The problems pile up if the server isn’t very responsive at the moment and it takes seconds rather than milliseconds to get a response. At times, the connection may even time out. Add to this the fact that multiple users could be attempting to perform this or another request at the same time, effectively clogging up the server. If your app crashes because of that, no emails will be sent either.

Now, this is often a hypothetical scenario. Reputable ESPs earned their reputations because of their reliability. Ping Postmark or Sendgrid and you’ll probably never have to wait more than 100-200ms for a response. Send them dozens of emails at once and they’ll handle them with ease.

As a matter of fact, most, if not all, of the popular ESPs send emails async anyway. It’s because of the underlying verifications each of them runs in the background, in attempts to protect their [sender reputation](https://mailtrap.io/blog/email-sender-reputation/).

None of these things change the fact that your app still connects to an external service every time an email is sent. That’s why you may want to consider adding an async capability to your app.
Learn how to send an email with Celery and Flask-Mail in the full article on [Email Sending with Flask](https://mailtrap.io/blog/flask-email-sending/).

## Testing emails in Flask

Before deploying any email functionality, you certainly need a way to test whether emails are actually sent without spamming users. 

You also may want to see some of those emails because chances are there will be a thing or two to improve.

The first part can be easily handled with simple Flask settings that will block sending. It can be done in two ways, with the identical outcome:

- Set _MAIL_SUPPRESS_SEND_ from the earlier configuration to _False_, or
- Add a new setting to the configuration file – _TESTING_ – and set it to _True_.

Then, you can use the record_messages method to see what’s being sent from your Flask app (make sure you have [blinker package](https://pypi.org/project/blinker/) installed). You’ll see the list of Message instances under outbox.

```
with mail.record_messages() as outbox:

    mail.send_message(subject='testing',
                      body='test',
                      recipients=emails)

    assert len(outbox) == 1
    assert outbox[0].subject == "testing"
```

If, however, you wish to see the emails that your app sends, you’ll need a different solution. Earlier in the text, we showed that Mailtrap can be easily plugged into a Flask app. It works as a fake SMTP, intercepting your outgoing emails and putting them into virtual inboxes.
 
Each email is visible in your Mailtrap dashboard. You can preview how it will look like on different screens. You may validate the headers and check the support for its HTML/CSS. 

Among other features, there’s a spam score, blacklists, bcc tracking, email forwarding, and multiple inboxes. It’s certainly a more comfortable method of testing than the one above, and you get to test a lot more than just sending.

Test it on your own! You can get started for free with [Mailtrap](https://mailtrap.io/register/signup).

Sending emails is a vital part of many Flask applications. When users create an account, a confirmation email should hit their inboxes right away. When they forget their password, a handy mechanism for resetting it built into an app will make their life a lot easier. 

There are tons of other situations when an auto-generated email is a must. Luckily, it’s really easy to set things up and send the first emails within minutes. Learn more about Flask-Mail and other options in our full article - [Sending Emails with Flask - Step-by-Step Flask-Mail Guide](https://mailtrap.io/blog/flask-email-sending/).