How to send bulk emails with attachments using Python and Flask

Introduction

In this tutorial I will show you how to send bulk emails with attachments using Python and Flask API. Flask API will be used to build the web based application and using Python’s email library we will send the email to multiple recipients. So sending bulk emails means sending an email to multiple recipients.

If you want you may attach multiple files in your email message. For attaching files I have given users option to choose multiple files using browse button. You can hold CTRL key while selecting multiple files.

I have put wysiwyg editor to compose the message. The email addresses should be separated by comma(,) when you are putting multiple email addresses.

You may find my other tutorials on email sending in Python language.

Prerequisites

Python 3.8.1, Flask 1.1.1, Gmail Security Settings, Gmail SMTP Server – gmail.smtp.com, Gmail SMTP Port – 587

Related Posts:

Creating Project Directory

Create a project root directory called python-flask-send-bulk-email as per your chosen location.

We may not mention the project’s root directory name in the subsequent sections but we will assume that we are creating files with respect to the project’s root directory.

Flask Configuration

We will configure application through flask framework.

We should create a flask instance to work on flask API.

Create a file called app.py with the below code.

from flask import Flask

app = Flask(__name__)
app.secret_key = "secret key"

Compose and Send Email

Now we will see how to compose and send email to multiple recipients. The file attachment is optional field and rest of the fields are mandatory.

Create a Python script called main.py and out the below source code.

In the above Python script, we first import smtplib for sending the email.

In the next line we import email module for creating email message.

We create the EmailMessage() object and set the body of the message using msg.add_alternative() function.

We set the subject for the email and we also set from and to email addresses to send and receive the email respectively.

We create a session using Gmail SMTP server – smtp.gmail.com and port – 587.

We need to issue STARTTLS command otherwise you will get the following error:

#smtplib.SMTPSenderRefused: (530, b'5.7.0 Must issue a STARTTLS command first. p7sm24605501pfn.14 - gsmtp', 'gmailaddress@gmail.com')

We attach the uploaded files in the email using add_attachment() function.

import smtplib
import mimetypes

from app import app
from werkzeug.utils import secure_filename
from flask import flash, render_template, request

from email.message import EmailMessage
from email.utils import make_msgid
		
@app.route('/')
def email_page():
	return render_template('emails.html')
	
@app.route('/send', methods=['POST'])
def send_email():
	subject = request.form['email-subject']
	body = request.form['email-body']
	emails = request.form['emails']
	
	if subject and body and emails:
	
		msg = EmailMessage()

		asparagus_cid = make_msgid()
		
		msg['Subject'] = subject
		msg['From'] = 'email@gmail.com'
		msg['To'] = (emails)
		
		msg.add_alternative(body.format(asparagus_cid=asparagus_cid[1:-1]), subtype='html')
		
		if 'email-attachments[]' in request.files:
			files = request.files.getlist('email-attachments[]')

			for file in files:
				filename = secure_filename(file.filename)
				
				ctype = mimetypes.MimeTypes().guess_type(filename)[0]
				
				if ctype is None:
					ctype = 'application/octet-stream'
					
				maintype, subtype = ctype.split('/', 1)
				f_data = file.read()
				
				msg.add_attachment(f_data, maintype=maintype, filename=filename, subtype=subtype)
				
		s = smtplib.SMTP('smtp.gmail.com', 587)

		s.starttls()

		s.login('email@gmail.com', 'gmail password')
		s.send_message(msg)
		s.quit()
		
		flash('Email successfully sent to recepients')
		
		return render_template('emails.html', color='green')
	else:
		flash('Email subject, body and list of emails are required field')
		
		return render_template('emails.html', color='red')
		
if __name__ == "__main__":
    app.run()

View File

As we are creating web based application to compose the email message for sending to multiple recipients so we need a view or template file.

In flask application, template file is kept under templates directory.

So we will create a file called emails.html inside the templates folder.

<!DOCTYPE html>
<html>
<head>
	<title>Python Flask Send Bulk Emails</title>
	<script src="https://cdn.tiny.cloud/1/no-api-key/tinymce/5/tinymce.min.js" referrerpolicy="origin"></script>
	<script>tinymce.init({selector:'textarea#email-body'});</script>
</head>
<body>
	<div style="width: 600px; margin: auto;">
		<div>
			{% with messages = get_flashed_messages() %}
			  {% if messages %}
				<ul style="color: {{ color }};">
				{% for message in messages %}
				  <li>{{ message }}</li>
				{% endfor %}
				</ul>
			  {% endif %}
			{% endwith %}
		</div>

		<div>
			<form action="/send" method="post" enctype="multipart/form-data">
				<h2>Compose and Send Email</h2>
				<dl>
					<p>
						<label><strong>Email Subject</strong></label>
						<input name="email-subject" value="{{ request.form['email-subject'] }}" type="text" placeholder="Email Subject" size="60"/>
					</p>
					<p>
						<label><strong>Email Body</strong></label>
						<textarea id="email-body" name="email-body" placeholder="Email Body">{{ request.form['email-body'] }}</textarea>
					</p>
					<p>
						<label><strong>List of Emails</strong>(separated by ,)</label>
						<textarea name="emails" placeholder="List of Emails" rows="6" cols="60">{{ request.form['emails'] }}</textarea>
					</p>
					<p>
						<label><strong>Email Attachments</strong></label>
						<input name="email-attachments[]" type="file" multiple="true"/>
					</p>
				</dl>
				<p>
					<input type="submit" value="Send Email">
				</p>
			</form>
		</div>
	</div>
</body>
</html>

In the above template file we have included a JavaScript file of TinyMCE editor. Make sure you are connected to internet otherwise you won’t be able to get the editor on your machine while you are running this example.

We also check for any success or error message and display them. We display messages from flash scope and for this we need session and for session we need secret key and that’s why I have configured Secret Key in app.py script.

Testing the Application

Now navigate to the project root directory and execute the command script main.py, your server will start on default port 5000.

If you want to change the port then you can change the line app.run() to app.run(port=50001), where 5001 is the new port.

The home page appears as shown below when you access the URL http://localhost:5000:

send bulk emails using python and flask

If you do not put the values for mandatory fields then you will get below error message:

send bulk emails using python and flask

Once email sent successfully to recipients then you will see below message:

send bulk emails using python and flask

That’s all.

Source Code

Download

Thanks for reading.

Leave a Comment