Question: I'm trying to learn asyncio. If I run this program normally without the asyncio library than it takes less time while it takes more time in this way so is this the right way to send mail using asyncio or there is any other way? import smtplib import ssl import time import asyncio async def send_mail(receiver_email): try: print(f"trying..{receiver_email}") server = smtplib.SMTP(smtp_server, port) server.ehlo() server.starttls(context=context) server.ehlo() server.login(sender_email, password) message = "test" await asyncio.sleep(0) server.sendmail(sender_email, receiver_email, message) print(f"done...{receiver_email}") except Exception as e: print(e) finally: server.quit() async def main(): t1 = time.time() await asyncio.gather( send_mail("test@test.com"), send_mail("test@test.com"), send_mail("test@test.com"), send_mail("test@test.com") ) print(f"End in {time.time() - t1}sec") if __name__ == "__main__": smtp_server = "smtp.gmail.com" port = 587 # For starttls sender_email = "*****" password = "*****" context = ssl.create_default_context() asyncio.run(main()) 

Answer: You are not really doing sending your emails correctly using asyncio. You should be using the aiosmtplib for making asynchronous SMTP calls such as connect, starttls, login, etc. See the following example, which I have stripped down from a more complicated program that handled attachments. This code sends two emails asynchronously: #!/usr/bin/env python3 import asyncio import aiosmtplib import sys from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText MAIL_PARAMS = {'TLS': True, 'host': 'xxxxxxxx', 'password': 'xxxxxxxx', 'user': 'xxxxxxxx', 'port': 587} async def send_mail_async(sender, to, subject, text, textType='plain', **params): """Send an outgoing email with the given parameters. :param sender: From whom the email is being sent :type sender: str :param to: A list of recipient email addresses. :type to: list :param subject: The subject of the email. :type subject: str :param text: The text of the email. :type text: str :param textType: Mime subtype of text, defaults to 'plain' (can be 'html'). :type text: str :param params: An optional set of parameters. (See below) :type params; dict Optional Parameters: :cc: A list of Cc email addresses. :bcc: A list of Bcc email addresses. """ # Default Parameters cc = params.get("cc", []) bcc = params.get("bcc", []) mail_params = params.get("mail_params", MAIL_PARAMS) # Prepare Message msg = MIMEMultipart() msg.preamble = subject msg['Subject'] = subject msg['From'] = sender msg['To'] = ', '.join(to) if len(cc): msg['Cc'] = ', '.join(cc) if len(bcc): msg['Bcc'] = ', '.join(bcc) msg.attach(MIMEText(text, textType, 'utf-8')) # Contact SMTP server and send Message host = mail_params.get('host', 'localhost') isSSL = mail_params.get('SSL', False) isTLS = mail_params.get('TLS', False) if isSSL and isTLS: raise ValueError('SSL and TLS cannot both be True') port = mail_params.get('port', 465 if isSSL else 25) # For aiosmtplib 3.0.1 we must set argument start_tls=False # because we will explicitly be calling starttls ourselves when # isTLS is True: smtp = aiosmtplib.SMTP(hostname=host, port=port, start_tls=False, use_tls=isSSL) await smtp.connect() if isTLS: await smtp.starttls() if 'user' in mail_params: await smtp.login(mail_params['user'], mail_params['password']) await smtp.send_message(msg) await smtp.quit() async def main(): email_address = 'xxxxxxxx'; co1 = send_mail_async(email_address, [email_address], 'Test 1', 'Test 1 Message', textType='plain' ) co2 = send_mail_async(email_address, [email_address], 'Test 2', 'Test 2 Message', textType='plain' ) await asyncio.gather(co1, co2) if __name__ == "__main__": asyncio.run(main())