Python automatically sends emails

A recent project at work has the need to automatically send some information emails to a specified mailbox. So how to use Python to implement the function of automatically sending emails? Let’s talk about it briefly next.

Python SMTP sends email

SMTP (Simple Mail Transfer Protocol) is a simple mail transfer protocol. To put it bluntly, it is a protocol for sending emails. Python’s smplib library simply encapsulates the SMTP protocol and provides support for SMTP. It can send plain text emails, HTML files, and Emails with attachments.

First, we build a SendEmailManager class, which also follows the idea of object-oriented programming. The general structure is as follows:

class SendEmailManager(object):

    def __init__(self, **kwargs):
        # Initialization parameters
        ...

    def _get_conf(self, key):
        # Get configuration parameters
        ...

    def _init_conf(self):
        #Initialize configuration parameters
        ...

    def _login_email(self):
        # Log in to the email server
        ...
    def _make_mail_msg(self):
        # Construct text mail object
        ...

    def do_send_mail(self):
        # Send email
        ...

def init(self, **kwargs)

The initialization function of a class can be used to set object attributes and give an initial value, which can be a parameter or a fixed value. The parameter **kwargs is to pass a dictionary of variable keyword parameters to the function actual parameters. Here we mainly It is to initialize the SMTP server (qq mailbox is used here), the proxy mailbox for sending mail, the client authorization password set in the mailbox, and the variable parameters. The specific code is as follows:

# SMTP server, use qq mailbox here, other mailboxes can be used by Baidu
EMAIL_HOST = 'smtp.qq.com'
# The proxy email address for sending emails
EMAIL_HOST_USER = '[email protected]'
# The client authorization password set in the mailbox. Note that this is not the mailbox password. For how to obtain the mailbox authorization code, please Baidu~~~
EMAIL_HOST_PASSWORD = 'xxxxxxxxxxxxx'
def __init__(self, **kwargs):
    # Initialization parameters
    self.email_host = EMAIL_HOST
    self.email_host_user = EMAIL_HOST_USER
    self.email_host_pass = EMAIL_HOST_PASSWORD
    self.kwargs = kwargs

def _get_conf(self, key)

Mainly responsible for reading the value in the variable parameter self.kwargs dictionary through key for use by other functions.

def _get_conf(self, key):
    # Get configuration parameters
    value = self.kwargs.get(key)
    if key != "attach_file_list" and (value is None or value == ''):
        raise Exception("configuration parameter '%s' cannot be empty" % key)
    return value

def _init_conf(self)

This function is mainly responsible for initializing the configuration parameters returned by the function _get_conf so that the following functions can call related configuration parameters.

def _init_conf(self):
    #Initialize configuration parameters
    print(self._get_conf('receives'))
    self.receives = self._get_conf('receives')
    self.msg_subject = self._get_conf('msg_subject')
    self.msg_content = self._get_conf('msg_content')
    self.msg_from = self._get_conf('msg_from')
    # attachment
    self.attach_file_list = self._get_conf('attach_file_list')

def _login_email(self)

Log in to the mail server. I am logging in to the qq mailbox server. The port number is 465. For other mailbox port numbers, please refer to Baidu. The code is as follows:

def _login_email(self):
    # Log in to the email server
    try:
        server = smtplib.SMTP_SSL(self.email_host, port=465)
        # set_debuglevel(1) can print out all information interacting with the SMTP server
        server.set_debuglevel(1)
        # Login E-mail
        server.login(self.email_host_user, self.email_host_pass)
        return server
    except Exception as e:
        print("mail login exception:", e)
        raise e

def _make_mail_msg(self)

The function of this function is to construct an email instance object to process the content of the email. A normal email generally has sender and receiver information, email subject, and email body. Some emails also have attachments. For specific settings, see the following code:

def _make_mail_msg(self):
    # Build mail object
    msg = MIMEMultipart()
    msg.attach(MIMEText(self.msg_content, 'plain', 'utf-8'))
    # Email Subject
    msg['Subject'] = Header(self.msg_subject, "utf-8")
    # Sender email information
    msg['From'] = "<%s>" % self.msg_from
    # msg['From'] = Header(self.msg_from + "<%s>" % self.email_host_user, "utf-8")
    msg['To'] = ",".join(self.receives)
    print("---", self.attach_file_list)
    if self.attach_file_list:
        for i, att in enumerate(self.attach_file_list):
            # Construct attachments and transfer files in the current directory
            if not att:
                break
            att_i = MIMEText(open(att, 'rb').read(), 'base64', 'utf-8')
            att_i["Content-Type"] = 'application/octet-stream'
            # The filename here can be written arbitrarily. Whatever name you write will be displayed in the email.
            att_i["Content-Disposition"] = 'attachment; filename="%s"' % att
            msg.attach(att_i)
    return msg

def do_send_mail(self)

To send an email, just string together the above functions and enter the code directly:

def do_send_mail(self):
    # Send email
    try:
        self._init_conf()
        server = self._login_email()
        msg = self._make_mail_msg()
        server.sendmail(self.email_host_user, self.receives, msg.as_string())
        server.close()
        print("Sent successfully!")
    except Exception as e:
        print("Mail sending exception", e)

Configure parameters and test whether emails can be sent normally:

if __name__ == "__main__":
    mail_conf = {
        'msg_from': '****@foxmail.com', # The address of the email sender
        'receives': ['****@qq.com',], # The address of the email recipient. This is a list, because there may be more than one recipient of the email.
        'msg_subject': 'Python send email test', # The subject of the email
        'msg_content': 'hello', # The content of the email
        'attach_file_list': {"test.py": "test.py", "test.txt": "./test.txt"}, # is a list of attachment file paths, this item is optional.
    }

    manager = SendEmailManager(**mail_conf)
    manager.do_send_mail()

image-20210702110038482ok, send Success, adding attachments is no problem. Now, we have implemented sending emails using Python, so how to automatically send emails? Next, let’s talk about it.

Send emails automatically

1. Code hard coding implementation

It is an infinite loop in the code, plus an if judgment, and the transmission is executed every 1 hour. The code is as follows:

def delayed_sending(manager):
    #The parameter manager is the SendEmailManager object
    begin_time = int(time.time())
    while True:
        end_time = int(time.time())
        if end_time - begin_time == 1*60*60:
            threading.Thread(target=manager.do_send_mail()).start()
            begin_time = end_time
            print("Sent...")

At the same time, in order to prevent unknown reasons from blocking the normal operation of the program, multi-threads are added to send emails asynchronously. In this way, after the program is executed, an email will be sent to the specified mailbox every hour. As long as the program does not stop, the emails will continue to be sent! !

Suppose we need to send an email to a specified mailbox at 8 o’clock every day, then we can do this:

def delayed_sending(manager):
    #The parameter manager is the SendEmailManager object
    hours = 8
    minute = 0
    second = 0
    while True:
    now = datetime.datetime.now()
    if now.hour == hour and now.minute == minute and now.second == second:
        threading.Thread(target=manager.do_send_mail()).start()
        print("Sent...")

Although the functions of the above two methods are realized, the implementation method is really low!

image-20210702161626809

2. Implement timing function through modules

In addition to hard coding, we can also implement it through the schedule module of the task timing runtime library in python:

# Use the python task timing runtime library schedule module
def send_mail_by_schedule(manager):
    schedule.every(20).minutes.do(manager.do_send_mail) # Execute every 20 minutes
    schedule.every().hour.do(manager.do_send_mail) # Execute once every hour
    schedule.every().day.at("10:00").do(manager.do_send_mail) # Execute once every day at 10:00
    schedule.every().monday.do(manager.do_send_mail) # Execute once every Monday
    schedule.every().friday.at("21:00").do(manager.do_send_mail) # Execute once every Friday at 21:00

    while True:
        schedule.run_pending()
        time.sleep(1)

Schedule is actually just a timer. In the while True infinite loop, schedule.run_pending() keeps the schedule running to query the above bunch of tasks. In the task, you can set different times to run. This is similar to crontab.

However, if multiple scheduled tasks are run, they are actually executed in order from top to bottom. If the above task is complex and takes a long time, it will affect the running time of the following tasks. If 5 tasks are run every 2 minutes, and each task takes 1 minute, it takes 5 minutes in total. In this way, when the next 2 minutes comes, the previous round of tasks is still running, and then a new round starts. Task. The solution is also very simple: use multi-threading/multi-process.

def run_threaded(manager):
    threading.Thread(target=manager.do_send_mail()).start()


# Use the python task timing runtime library schedule module
def send_mail_by_schedule(manager):
    schedule.every(1).minutes.do(run_threaded, manager) # Execute every 20 minutes
    schedule.every().hour.do(run_threaded, manager) # Execute once every hour
    schedule.every().day.at("10:00").do(run_threaded, manager) # Execute once every day at 10:00
    schedule.every().monday.do(run_threaded, manager) # Execute once every Monday
    schedule.every().friday.at("21:00").do(run_threaded, manager) # Execute once every Friday at 21:00

    while True:
        schedule.run_pending()
        time.sleep(1)

In this way, we can create a thread for each scheduled task and let the task run in the thread, thereby achieving the effect of multiple tasks working in parallel. Does this method save time and effort than the first method? It doesn’t require a lot of code at all. It’s perfect!

Summary

In fact, to put it bluntly, the most important thing about automatically sending emails is to realize the automatic execution of tasks, and there are many implementation solutions. For example, you can also use an asynchronous task scheduler similar to celery to manage the queue. Monitor to realize automatic execution of tasks, etc.

After completing the automatic sending of emails, we can also let the program send us weather forecasts, daily news, chicken soup, etc. every day (it can also be sent to male and female friends) hahaha.

The rapid rise of Python is extremely beneficial to the entire industry, but “There are many popular people and not many people“, which has led to a lot of criticism, but it still cannot stop its popularity. development momentum.

If you are interested in Python and want to learn Python, here I would like to share with you a Complete set of Python learning materials, which I compiled during my own study. I hope it can help you, let’s work together!

Friends in need can click the link below to get it for free or Scan the QR code below to get it for free
Python complete set of learning materials

1Getting started with zero basics

① Learning route

For students who have never been exposed to Python, we have prepared a detailed Learning and Growth Roadmap for you. It can be said to be the most scientific and systematic learning route. You can follow the above knowledge points to find corresponding learning resources to ensure that you learn more comprehensively.

② Route corresponding learning video

There are also many learning videos suitable for beginners. With these videos, you can easily get started with Python~

③Exercise questions

After each video lesson, there are corresponding exercises to test your learning results haha!

2Domestic and foreign Python books and documents

① Documents and books

3Python toolkit + project source code collection

①Python toolkit

The commonly used development software for learning Python is here! Each one has a detailed installation tutorial to ensure you can install it successfully!

②Python practical case

Optical theory is useless. You must learn to type code along with it and practice it in order to apply what you have learned to practice. At this time, you can learn from some practical cases. 100+ practical case source codes are waiting for you!

③Python mini game source code

If you feel that the practical cases above are a bit boring, you can try writing your own mini-game in Python to add a little fun to your learning process!

4Python interview questions

After we learn Python, we can go out and find a job if we have the skills! The following interview questions are all from first-tier Internet companies such as Alibaba, Tencent, Byte, etc., and Alibaba bosses have given authoritative answers. I believe everyone can find a satisfactory job after reviewing this set of interview materials.

5Python part-time channels

Moreover, after learning Python, you can also take orders and make money on major part-time platforms. I have compiled various part-time channels + part-time precautions + how to communicate with customers into documents.

All the above information , if friends need it, you can scan the QR code below to get it for free