Sending Email (Flask-Mail)
Sending email means building a message with a subject, recipients, and a body, then handing it to an SMTP server that delivers it to the inbox.
Learn Sending Email (Flask-Mail) in our free Flask course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick…
Part of the free Flask course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
In this lesson you'll build real email payloads with Python's standard library, add HTML bodies and attachments, send one from a route, and see the Flask-Mail equivalent.
Every email is just structured data: a subject , a from address, one or more recipients , and a body . Flask-Mail's Message object holds exactly these fields. Under the hood it's the same structure as Python's standard-library EmailMessage , which we can build and inspect runnably.
The example below assembles a welcome email and prints its headers and body — this is precisely the payload that would be handed to an SMTP server.
The printout shows the subject, the from/to pair, and the body — the four pieces every message needs before it can be sent.
Real product emails are formatted. You send an HTML version for clients that render it and keep a plain-text version as a fallback. Technically this is a multipart/alternative message holding a text/plain and a text/html part.
The runnable example sets the plain body with set_content and adds the HTML with add_alternative , then prints the resulting multipart structure to prove both parts are present.
The common case is sending mail in response to a user action — a contact form, a password reset, an order confirmation. You read the form data, build the message, and send it. The runnable example does all of that against an in-memory "outbox" so you can see it work end to end, and even shows an attachment.
Complete the message below. Replace each ___ to set the recipient and the body.
Your MAIL_USERNAME / MAIL_PASSWORD are wrong, or the provider needs an app-specific password. For Gmail you must create an app password — your normal login won't work over SMTP.
You called mail.send() outside a request or app context (for example in a background thread). Wrap it in with app.app_context(): so Flask-Mail can read your config.
Build personalized newsletters for a list of subscribers.
Lesson complete — your app can reach the inbox!
You built real email payloads with subject, from, recipients, and body, added HTML with a text fallback and an attachment, sent one from a route, and saw the Flask-Mail API.
🚀 Up next: Logging & Monitoring — see what your app is doing in production.
Practice quiz
Which extension is commonly used to send email from Flask?
- Flask-Mailer
- Flask-Mail
- Flask-SMTP
- Flask-Inbox
Answer: Flask-Mail. Flask-Mail provides the Mail object and Message class for sending email.
What protocol delivers email between mail servers?
- SMTP
- HTTP
- FTP
- IMAP-send
Answer: SMTP. SMTP (Simple Mail Transfer Protocol) accepts and relays outgoing mail.
How do you create a message in Flask-Mail?
- Mail(subject, ...)
- Email(subject, ...)
Message(subject, recipients=[...]) builds the email; mail.send delivers it.
Which method actually delivers a Flask-Mail message?
- msg.deliver()
- msg.post()
- Mail.dispatch(msg)
- mail.send(msg)
Answer: mail.send(msg). mail.send(msg) hands the message to the configured SMTP server.
Which config key sets the SMTP host for Flask-Mail?
- MAIL_SERVER
- MAIL_HOST
- SMTP_SERVER
- MAIL_URL
Answer: MAIL_SERVER. MAIL_SERVER names the SMTP host, e.g. smtp.gmail.com.
How do you set the rich HTML body on a Flask-Mail Message?
- msg.render = ...
- msg.html = '<p>...</p>'
- msg.content_html(...)
- msg.set_html(...)
Answer: msg.html = '<p>...</p>'. msg.html holds the HTML version; msg.body holds the plain-text fallback.
Which Message attribute holds the plain-text fallback?
- msg.text
- msg.plain
- msg.body
- msg.content
Answer: msg.body. msg.body is the plain-text version shown by clients that do not render HTML.
How do you attach a file to a Flask-Mail message?
- msg.file(name, data)
- msg.add_file(data)
- msg.append(name, data)
- msg.attach(name, content_type, data)
Answer: msg.attach(name, content_type, data). msg.attach(filename, content_type, data) adds the file's bytes to the message.
Which port is typically used for SMTP over TLS?
- 587
- 21
- 8080
- 3306
Answer: 587. Port 587 is standard for SMTP with TLS (465 for SSL).
Why enqueue email as a background task for bulk sending?
- SMTP is free only in background
- email cannot run in a route
- an SMTP send can take seconds and block the request
- Flask-Mail requires Celery
Answer: an SMTP send can take seconds and block the request. Slow SMTP round-trips block the request; a worker lets the response return immediately.