Sending Email
Django's email framework is a thin wrapper over Python's SMTP tools that lets you compose and deliver messages — plain text or HTML — through a configurable backend with one function call.
Learn Sending Email in our free Django course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free Django 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 fire off a quick message with send_mail , take full control with EmailMessage , preview mail in the console backend, and build templated HTML emails using EmailMultiAlternatives and render_to_string .
The quickest way to send mail is send_mail(subject, message, from_email, recipient_list) . Where that mail goes is decided by EMAIL_BACKEND . In development you use the console backend , which prints the full email to your terminal instead of contacting a real server.
When you need more than a basic message, build an EmailMessage object. You can add cc , bcc , reply_to , custom headers, and attachments, then call .send() . It's the class send_mail uses under the hood.
For rich email you send both a plain-text and an HTML version using EmailMultiAlternatives . You render each body from a template with render_to_string , set the plain text as the body, and attach the HTML as an alternative. Clients pick whichever they support.
send_mail returns how many messages were sent. Fill in the blank so the return value equals the number of recipients in the list.
❌ Connection refused / SMTP error in development
You're using the SMTP backend with no mail server running locally.
✅ Fix: set EMAIL_BACKEND to the console backend while developing so mail just prints.
You passed a bare string for the recipients, e.g. recipient_list="ada@example.com" .
✅ Fix: always wrap addresses in a list — ["ada@example.com"] .
You put HTML into the plain message argument instead of attaching it as an alternative.
✅ Fix: use EmailMultiAlternatives and attach_alternative(html, "text/html") .
Write a function that renders an order-confirmation subject and body from a context dictionary, then returns the full payload send_mail would deliver.
Lesson complete — your app can talk to the world!
You can send a quick message with send_mail , take full control with EmailMessage , preview mail through the console backend, and build templated HTML email with EmailMultiAlternatives and render_to_string .
🚀 Up next: The Caching Framework — make pages fast by storing expensive results with cache.set and @cache_page .
Practice quiz
Which function is the simplest way to send a plain-text email?
- mail()
- send_mail()
- deliver()
- EmailMessage.send_now()
Answer: send_mail(). send_mail() is a convenience function taking subject, message, from, and recipient list.
What arguments does send_mail() take in order?
- recipient_list, subject, message, from_email
- from_email, subject, recipient_list, message
- subject, message, from_email, recipient_list
- message, subject, recipient_list, from_email
Answer: subject, message, from_email, recipient_list. send_mail(subject, message, from_email, recipient_list) is the standard signature.
Which class gives full control over cc, bcc, and attachments?
- EmailMessage
- send_mail
- SimpleMail
- MailSender
Answer: EmailMessage. EmailMessage is the underlying class exposing cc, bcc, reply-to, headers, and attachments.
Which EMAIL_BACKEND prints emails to the terminal in development?
- smtp.EmailBackend
- filebased.EmailBackend
- dummy.EmailBackend
- console.EmailBackend
Answer: console.EmailBackend. django.core.mail.backends.console.EmailBackend prints the full email to the console.
Which class lets you send both plain-text and HTML versions?
- EmailMultiAlternatives
- HtmlEmail
- send_mail with html=True
- EmailMessage.as_html()
Answer: EmailMultiAlternatives. EmailMultiAlternatives lets you attach_alternative(html, 'text/html') alongside the plain body.
What does render_to_string return?
- An HttpResponse
- The rendered template as a Python string
- A template object
- A file path
Answer: The rendered template as a Python string. render_to_string renders a template with a context and returns the output as a string, ideal for email bodies.
How do you add the HTML version on an EmailMultiAlternatives message?
- msg.set_html(html)
- msg.html = html
- msg.attach_alternative(html, 'text/html')
- msg.add_html(html)
Answer: msg.attach_alternative(html, 'text/html'). attach_alternative(html_content, 'text/html') adds the HTML alternative.
Which backend do you switch to for sending real mail in production?
- console.EmailBackend
- dummy.EmailBackend
- locmem.EmailBackend
- smtp.EmailBackend
Answer: smtp.EmailBackend. The SMTP backend, configured with EMAIL_HOST, EMAIL_PORT, and credentials, sends real mail.
When should you use EmailMessage instead of send_mail?
- When you need attachments, cc, or bcc
- For every email
- Only in development
- Never — send_mail does everything
Answer: When you need attachments, cc, or bcc. Use EmailMessage when you need extra features like attachments, cc, bcc, or custom headers.
What does send_mail() return?
- The EmailMessage object
- None
- The number of messages successfully sent
- The recipient list
Answer: The number of messages successfully sent. send_mail() returns the number of successfully delivered messages.