Automate Emails Using Python! Build An Automatic Payment Reminder & Schedule Your Scripts Online

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Hey guys, In this video, I will show you how you can send and schedule emails using Python. In particular, we will build a Payment reminder tool. And here is how it works. I have here a Google Sheets document to keep track of my invoices. So, we have here the customer's email, name, invoice number, invoice amount, the payment due date and if the invoice has already been paid or not. Once the due date has passed and the invoice is still open, I want to send out a payment reminder email on the reminder date. And in this video, we will automate the whole process. So, I will show you how to process the spreadsheet data and send emails using Python. Once that is working, we will deploy our script to the cloud and schedule it. For this example, I will run the script daily. So, every day Python will access the spreadsheet and automatically send emails if the conditions are met. OK, and without further ado, let us get started. First things first, let us install the required dependencies for this project. We only need two packages: pandas and python-dotenv. Therefore, spin up your terminal or command, type "pip install pandas" and "python-dotenv", and hit enter. Now, before we jump into coding out the solution, I will do some setup regarding our email credentials. Later, when sending out emails, we will need to authenticate ourselves using our email address and password. Somewhere you need to store that information. A bad place would be your Python script, especially if you plan to upload your project to the internet, for instance, to GitHub. It would be better to store that kind of information in your environment variables. To do so, I will first create a "dot env" file. Just make a standard text file and rename it accordingly. In this file, I will write my email address and password. So, this is the password I am using to login into my account. Now, you want to avoid uploading this file to GitHub. Therefore, we will create a gitignore file. Just head over to the following website. Here, type "Python" and click on the create button. Copy the whole text to your clipboard and create a new file called ".gitignore". In this new file, paste the text you just copied. Here you can now see all the files and folders git will ignore. If you scroll up a bit, you will see that our ".env file" will also be ignored. Great, now that we have all the preparation out of the way, let us get down to the actual coding part. To kick things off, let us see how to send emails with Python. Therefore, I am creating a new python file and naming it "send_email.py". Open this file with your preferred text editor. First, I will import the required modules. Os, smtplib, email and pathlib are all core python modules. So, they are already included in your Python installation. Next, we will also import load_dotenv from dot env. After our imports, I will specify the port and email server for outlook. And here is one important point which I want to highlight. As you noticed already, I am using my outlook email address. You might want to use a different email provider like Gmail or iCloud. In that case, you would need to change the email server and the port. Because those will be different depending on which email provider you are using. Also, for Gmail, you must go through the 2-step verification process. In this video, I cannot cover the setup for all email providers. But as I said, you usually only need to change the server address. You might also need to adjust the port if you send emails with SSL. Ok, and with that said, let us now load our environment variables, so the email address and password. Our ".env" file is located in the current directory. To get the path to the current directory, I am using the pathlib module. Now, this line might look convoluted. But it will just return the current folder of my Python file. I have included the if statement so that it will also work in Jupyter Notebooks. And with that, we can now use the load_dotenv function with our file path. To retrieve the values, we can use os.getenv followed by the name. So, here I am getting my email address and password. Now that we have that let me create some more space and define the actual function to send an email. Later, when sending out the emails, I would include some variables to keep things dynamic. So, this function will take the subject, receiver email, name, due date, invoice number and amount as input arguments. Creating an email is fairly easy. First, we will initialise an EmailMessage object. We can then use this object to add our components to it. So, we can add a subject, the sender and receiver address and optionally, we could also specify the CC or BCC. You will notice that I have used "formataddress" for the sender email. Adding this will give our email a nice touch. Instead of the pure email address, the receiver will see the name we specify here. So, this could be your company name, for instance. After setting up those things, let us create the email body. Let me first type out the entire message, and then I will explain it. I am using here an f-string to include our variables. So, later, we will replace the name, amount, invoice number and due date. This is now our plain text version and will be our backup solution. Because, nowadays, almost all email softwares out there support HTML emails. That means we can also write an HTML version of our email. This has the advantage of customising the look of the text further. To add the HTML version, simply type "msg.add_alternative" followed by the HTML text. As before, let me type out the message before going over it. The text itself is the same. Yet, this time, I have included HTML tags. For example, I use the "strong" tag to highlight the amount and due date to make the font bold. Additionally, I have also set the subtype to HTML. Now that we also have our email text in place, we are ready to send it. To do so, I am going to use a context manager. By the way, SMTP stands for Simple Mail Transfer Protocol, and it is an application used by mail servers to send and receive emails. To interact with that server, we need to specify the server address and the port number. Next, we will need to establish a connection. For this, I am using the protocol command "STARTTLS". Once we have a connection, we can log into our account before sending the message. Alright, and that is all there is to it. Before we test it out, I want to add one more important "if-condition". You might have seen this boilerplate code before. I will not go into the details on how it works, but later in the video, I want to import this Python script as a module. When important other files, Python will execute them. To avoid that we are running our script just by important them, I have included this if condition. However, when we run the file directly, the following lines will be executed. So, to test things out, I will now call your "send email" function and provide the required parameters. After executing the script, we should now have sent a new email to this address. To validate this, let me go back to the browser and navigate to my Gmail inbox. And indeed, here we can see our email from the coding is fun corporation. When I open the mail, we can also see that the placeholders got replaced and that the amount and due date are displayed in bolt. Great, now that we know that is working, let us move on to the next step. In the final application, I want to send emails based on my spreadsheet. I have already prepared a simple google sheets document. In the spreadsheet, you will notice that I have included the variables we will need later on. So, we have here the email, name, invoice number, amount and due date. Additionally, I have added two more columns. One for the reminder date and the information if a customer has paid already. So, the idea is that we will send out the emails on the reminder date if the invoice has not been paid yet. It depends, of course, on how you want to set up things. But I thought this could be like a real-world application, where you might want to give the customers a bit more time before sending out an invoice reminder. Ok, now that we have all the information in google sheets, we need to access it somehow with Python. And there are two possible routes you can go – a secure and a not-so-secure one. We will use the less secure option by sharing our spreadsheet with the public. But there are many tutorials here on YouTube on accessing your spreadsheet using your credentials, which is, of course, more secure. Yet, it requires a bit more setup, and I wanted to keep this tutorial as brief as possible. And with that said, let me share my spreadsheet and change the general access permission down here. As mentioned, this is not secure, as anybody on the internet with the link could view your spreadsheet, but regardless, I will confirm my action by clicking Done. Ok, now that we have this place, let us go back to our folder and create a new Python file. I will name this file "main.py". By the way, the naming is important here. Later, when we are deploying our python script, the web server will look for a "main.py" file. With that said, let's open the file. Essentially, we want to use this script to loop over our spreadsheet and send emails if our conditions are met. For this, we will need the built-in python module DateTime. To work with the spreadsheet, I also import pandas as pd and finally, we will use our local python module "send email". After our imports, let us define the URL to our google sheets file. And here I will show a cool hack. Without much effort, we could convert your google sheets document to a CSV file. In doing so, we can easily read it as a pandas dataframe. To convert it to CSV, I will define the sheet id, sheet name, and URL as variables. Within the URL, I have used an f-string to insert our sheet id and name. You can find your ID in your browser. If you go back, you want to copy this part of the URL to your clipboard. Back in the script, I will paste it right here. And the sheet name was "sheet1". As I said, we can now load our spreadsheet into a pandas dataframe. To do this, I will define a new function, which will take our URL as an input parameter. As we are also dealing with dates, I will tell pandas the column's name, which should be converted to a DateTime object. In my case, the column names are "due date" and "reminder date". Next, we can use pd.read_csv followed by the URL and the parse dates arguments before returning the dataframe. Ok, and before going further, let us test it by printing out the dataframe. If I run the script, I can see the data down here. Great, now that we have our dataframe, let us use pandas to query the data. For this, I will yet create another function. We need to know today's date to check whether we want to send out the reminder email. For this, I am using "date.today". Next, I will initialise an email counter variable to keep track of all emails we have been sent while running the code. With that in place, I will iterate over our dataframe. As mentioned, I only want to send an email if the reminder date is today or has already passed. In addition, Python should only send emails if the invoice has not been paid yet. If both criteria are met, we will trigger our send_email function. As seen already, this function will take a couple of arguments, which I can get from the current row, like the invoice number, receiver email, name, due date and amount. For the due date, I converted the date-time object to a human-readable output string, like the 11th of August, 2022. After sending the email, I will increase our email counter. Once we have looped over the entire dataframe, I will return a string with the total number of emails sent. Alright, and that is all there is to it. Like before, let me also test it out by converting our spreadsheet into a pandas dataframe. Then, I will pass the dataframe to our function, print out the result and execute our code. At the time of this recording, it is the 12th of August. That means Python should have sent out two emails. Let me validate this by navigating to my Gmail inbox. And indeed, here I can see my new email. Python sent the other mail to a temporary inbox. When I navigate to that site, we will also see our invoice reminder from the coding is fun corporation. Great, this seems to be working. The neat thing is that I could now simply adjust our spreadsheet to determine whether we should send an email or not. Let us say Kumar has paid the invoice. After updating the spreadsheet and rerunning the script, only Sven should get an email. So, once again, I will navigate to my Gmail inbox, and voila, we can see the email. For the final test, I will change the reminder date to the 13th of August. So, with this setting, Python should not send any email. And also, this works. After executing the script, I can see that no email has been sent out. As this is all working, we are ready to move on to the last step - the deployment on a server. Because ideally, we do not want to trigger our Python script manually. Instead, we want to schedule it on a server that will run our script daily. Before deploying it, we need to let the server know which external libraries we need. For this, I will create a "requirements.txt" file. Within this file, I will simply type pandas and python-dotenv. Now, there are many cloud platforms available. My absolute favourite cloud provider is deta. And the cool thing is that deta is offering their service for free. All you need to do is to head over to their website at "deta.sh". On this website, go ahead and create a new account. I already created one for myself. After you have set up your account, navigate to the documentation page. Deta offers different services. We are interested in the cloud instance called "Deta Micros". Navigate to that section and click on "Getting started". Here you can find the detailed instructions for your operating system. As I am on a Windows machine, let me switch to Windows. The first thing you want to do is to download and install the deta command line interface tool. The setup is super easy. Just copy this link and open up Powershell on your computer. Before going further, let me shortly navigate to our project folder by using "CD". Next, I will paste the command we just copied and press enter. Once deta has been installed, you can use "deta" commands in your terminal. So, we can now log in to our deta account by running "deta login". This will open up the browser, and you should be able to login it. If that works for you, we can now create our first micro by going back to the documentation and copying the following command. You want to paste that command into your terminal. Ensure that you are in the correct folder. In my case, the Python file is located on my Desktop in a folder called "Automate Emails". Feel free also to change the micro name. For instance, I will call mine email automation. After pressing enter, you should see a message which looks like this. If that is the case, you should now have a new folder in your directory. Here, you can find a deta folder and a "main.py" file. I am only interested in the deta folder. So, let me cut out this folder and paste it into our root directory. With that, I can delete the additional folder deta has created. Ok, guys, we are almost done. We will just need a couple of more commands. First, let us check if we can see the micro in our dashboard. By the way, I am using deta also for a couple of other projects; that I why, you can see more micros here. But I can also see our email automation instance. In the visor tab, you can check if your script is running as expected. By default, this view is disabled. You can enable it by running "deta visor enable" in your terminal. Once that is done, let me refresh my dashboard. Ok, now we access the visor. So far, we have not deployed anything to our instance yet. That is why you cannot see much here. And before deploying our script, we also need to do two more important steps. The first one is in regards to our environment variables. As you know, we will need our email address and password in our script. This information is stored in the 'dot.env' file and our environment variables. Also, in deta, you can set environment variables. To do so, you just need to run "deta update -e" followed by the name of the file. After running this command, we securely transferred the email address and password to our instance. Next, we also need to tell deta when to run our script. We will do this by setting up a cron job. Back in the documentation, you can find a boilerplate code if you scroll down a bit. We will need to implement this piece of code in our "main.py" file. Therefore let me copy it to my clipboard and open our python file. I will paste it at the very bottom of the script. Within the cron job function, we will define the action we want to perform. In our case, we want to first load our dataframe before iterating over our dataset and sending out the emails. Once that is done, we will return the result. Lastly, I will move the import statement to the other imports. By the way, deta is also a third-party package. Yet, this package is already installed on our micro instance by default. So, that is why I have not included it in our "requirements.txt" file. Alright, and with that, we are ready to deploy our script. And this is very straightforward. Just type deta deploy and press enter. Running this command for the first time might take some time, as deta needs to install the required packages. But once that is done, we can determine via cron expression when to run our script. In the documentation, you can already find some examples. For instance, you could run it daily at 10 am UTC. So, I recommend checking out this page to set your cron job to your specific needs. For testing purposes, I will run the script every minute. Therefore, let me copy the following line. Back in my terminal, I will paste it and hit enter. If everything worked, we should see our return message in the deta visor dashboard. And indeed, we can see that the script runs successfully, but zero emails have been sent. And this is expected. Because if we go back to our spreadsheet, none of our conditions is met. So therefore, let me change back the reminder date to the 12 of August. So the day of this recording. Now, if we go back to our dashboard and wait for around one minute, we will see that our script ran again. One email has been sent this time, and we could also validate this by navigating to my Gmail inbox. And voila, here is our invoice reminder. For the final test, I will change "has_paid" to no. So, this time we should see two emails. And indeed, if we take a look here, this is also what our script returns. As before, we could also validate this by checking the disposal and Gmail inbox. Ok, guys, and this is how you can automate emails and schedule your scripts online for free. If you want to change the schedule, you could simply overwrite the cron job, or in my case, I will remove it by running "deta cron remove". And remember that any changes you make in your Python file locally will not be automatically deployed. So, if you later add more Python files or change the current ones, open your terminal in the root folder, log in with "deta login", and deploy your changes by running "deta deploy" one more time. Ok, guys, and that is all I have for you today. As always, thanks for watching and see you in the next video.
Info
Channel: Coding Is Fun
Views: 53,790
Rating: undefined out of 5
Keywords: Coding is fun, email automation, emails with python, send emails using python, schedule python scripts, deploy python to deta, deta tutorial, deta schedule scripts, run python scripts online, payment reminder, python payment reminder, python automation, python automation project, access google sheets using python, python and google sheets, spreadsheet automation, invoice reminder python, python tutorial, learn python
Id: OLrC4J2-pvk
Channel Id: undefined
Length: 21min 23sec (1283 seconds)
Published: Sun Aug 21 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.