{"id":4422,"date":"2020-06-04T12:22:12","date_gmt":"2020-06-04T10:22:12","guid":{"rendered":"https:\/\/www.cosmicdevelopment.com\/?p=4422"},"modified":"2024-01-22T15:57:33","modified_gmt":"2024-01-22T14:57:33","slug":"how-to-send-scheduled-emails-with-the-programming-language-python","status":"publish","type":"post","link":"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/","title":{"rendered":"How to Send Scheduled Emails with Python"},"content":{"rendered":"\n<h5 class=\"wp-block-heading\">By Nikola Dokoski<\/h5>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<p class=\"has-medium-font-size\"><em>Witnessing the rise of Python, we can&#8217;t help but notice its implementation in almost every aspect of our lives. From its general purpose for developing GUI applications, web applications, and websites, to its core functionality, which is to take care of the common programming tasks, Python is certainly classified as a high-level programming language. With that being said, Python has a simple syntax that makes the code base readable and maintainable. There are many other <\/em><a aria-label=\" (opens in a new tab)\" href=\"https:\/\/www.cosmicdevelopment.com\/blog\/advantages-of-using-the-python-programming-language-in-the-new-decade\/\"><em>advantages of using Python<\/em><\/a><em>, especially its easy-to-use feature that separates it from other programming languages.&nbsp;<br><\/em><\/p>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<figure class=\"wp-block-gallery aligncenter has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image\"><img fetchpriority=\"high\" decoding=\"async\" width=\"1024\" height=\"540\" data-id=\"4475\" src=\"http:\/\/staging.cosmicdevelopment.info\/wp-content\/uploads\/2020\/06\/screenshot_from_2020-06-02_13-10-39-1-1024x540.png\" alt=\"Code on how to send scheduled emails with Python programming language\" class=\"wp-image-4475\" srcset=\"https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/screenshot_from_2020-06-02_13-10-39-1-1024x540.png 1024w, https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/screenshot_from_2020-06-02_13-10-39-1-300x158.png 300w, https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/screenshot_from_2020-06-02_13-10-39-1-768x405.png 768w, https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/screenshot_from_2020-06-02_13-10-39-1-1536x810.png 1536w, https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/screenshot_from_2020-06-02_13-10-39-1-370x195.png 370w, https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/screenshot_from_2020-06-02_13-10-39-1-760x401.png 760w, https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/screenshot_from_2020-06-02_13-10-39-1.png 1847w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/figure>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p class=\"has-medium-font-size\"><em>In this article, <\/em><strong><em>Nikola Dokoski<\/em><\/strong><em> covers a few methods for automatically sending email messages using Django. His basic idea is to create a Django project where he will present a model for holding scheduled mail, add a management command to send scheduled emails manually, and finally cover a few methods to automate this process.<br><\/em><\/p>\n\n\n\n<p class=\"has-medium-font-size\"><em>Nikola will explain the entire process &#8211; if you are interested in the main bits of code as well as a <\/em><code><em>`tar.gz`<\/em><\/code><em> that you can install via pip, just scroll to the end.<\/em><\/p>\n\n\n\n<p class=\"has-medium-font-size\">Let&#8217;s start off with some basic stuff.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">I will be using a virtualenv for this article. I recommend that you use it too &#8211; you can install it via <code>`pip install virtualenv`<\/code> and check out the docs at <code>https:\/\/pypi.org\/project\/virtualenv\/1.7.1.2\/<\/code><\/p>\n\n\n\n<p class=\"has-medium-font-size\">Create a venv and install Django:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>virtualenv venv\nsource venv\/bin\/activate\npip install django # At the time of writing, I am using django 3.0.6.<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">Then we create the project and the app.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>django-admin startproject auto_mail\ncd auto_mail\npython manage.py migrate # For default models - users and whatnot.\npython manage.py startapp mail_app<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">We won&#8217;t really be creating any views and URLs here &#8211; we will just use the models, admin, and management modules. This makes the app easier to use and to add to other projects.<br>On that end, we want a model for a scheduled mail.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># in mail_app\/models.py\n\nclass MailAttachment(models.Model):\n\tattachment_file = models.FileField()\n\tattached_to = models.ForeignKey('ScheduledMail', related_name = 'attachments', on_delete = models.CASCADE)\n\n\tdef __str__(self):\n    \treturn '%s (%s)' % (self.attachment_file.filename, self.attached_to.subject)\n\n\nclass MailRecipient(models.Model):\n\tmail_address = models.CharField(max_length = 40)\n\n\tdef __str__(self):\n    \treturn self.mail_address\n\n\nclass ScheduledMail(models.Model):\n\tsubject = models.CharField(max_length = 40)\n\ttemplate = models.FileField(upload_to = 'mail_app\/mails')\n\tsend_on = models.DateTimeField(default = timezone.now())\n\trecipients_list = models.ManyToManyField(MailRecipient, related_name = 'mail_list')\n\n\tdef __str__(self):\n    \treturn self.subject<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">Fairly simple. We have a ScheduledMail model, which is the basis for this app that holds a subject and a template. We have the template as a file because, well, we may want our mail to be formatted nicely as an HTML message. If we were to use a standard CharField, it would have to be with a really high max length, which is not the best for use in a database, so way better is to just upload files. Furthermore, we can create a better method of creating mails via a view, as well as preview and whatnot, then save it to a file and upload it.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">The other models \u2013 MailAttachment and MailRecipient \u2013 will allow us to add multiple users and attachments to our mail messages. With that, we have most of what our app will be using! We just need to write a management command.<br><\/p>\n\n\n\n<p class=\"has-medium-font-size\">Before we do that though, let\u2019s create the database. For development, I just go with sqlite3, as it\u2019s easy to backup and play around with. You might want to use PostgreSQL or something heavier for production. So, let us add our app in the project settings, under INSTALLED_APPS. Also, since we are using a FileField for our mail template, we also need to define MEDIA_ROOT and MEDIA_URL values so that our files can be uploaded properly.&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># in auto_mail\/settings.py\n...\nINSTALLED_APPS = &#91;\n\t'django.contrib.admin',\n\t'django.contrib.auth',\n\t'django.contrib.contenttypes',\n\t'django.contrib.sessions',\n\t'django.contrib.messages',\n\t'django.contrib.staticfiles',\n\t'mail_app',\n]\n\nMEDIA_URL = '\/media\/'\nMEDIA_ROOT = 'media\/'<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">And now we can migrate:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>python manage.py makemigrations\npython manage.py migrate<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">One last step before finally viewing the admin &#8211; registering the models. Add this to your app&#8217;s admin.py folder:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># in auto_mail\/admin.py\nfrom django.contrib import admin\nfrom .models import ScheduledMail, MailAttachment, MailRecipient\n\n# Register your models here.\n\n@admin.register(ScheduledMail)\nclass MailAdmin(admin.ModelAdmin):\n\tpass\n\n@admin.register(MailAttachment)\nclass AttachmentAdmin(admin.ModelAdmin):\n\tpass\n\n@admin.register(MailRecipient)\nclass RecipientAdmin(admin.ModelAdmin):\n\tpass<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">And finally, create a superuser and run the server:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>python manage.py createsuperuser\npython manage.py runserver<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">Great, we have our models, we can add mails, add recipients, and so on. Let&#8217;s create the actual command. And, well, it&#8217;s pretty simple.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir -p mail_app\/management\/commands\ntouch mail_app\/management\/commands\/__init__.py\ntouch mail_app\/management\/__init__.py<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">After this, we just need to add our send mail command in that folder. To keep the code clean, let us add all mail functionalities in the models themselves.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># in mail_app\/models.py\n\nfrom django.conf import settings\n\nauto_mail_from = 'from@mail.com'\nif hasattr(settings, 'AUTO_MAIL_FROM'):\n\tauto_mail_from = settings.auto_mail_from\n\nclass ScheduledMail(models.Model):\n\n\n        ...\n\t@classmethod\n\tdef get_today_mail(cls):\n    \ttoday = date.today()\n    \treturn cls.objects.filter(send_on__year = today.year, send_on__month = today.month, send_on__day = today.day)\n\n\tdef send_scheduled_mail(self):\n    \tmessage = self.template.read().decode('utf-8')\n    \trecipient_list = list(self.recipients_list.values_list('mail_address', flat = True))\n    \tmail_msg = EmailMessage(\n        \tsubject = self.subject,\n        \tbody = message,\n        \tfrom_email = settings.AUTO_MAIL_FROM,\n        \tto = recipient_list,\n    \t)\n    \tmail_msg.content_subtype = 'html'\n\n    \tmail_msg.send()<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">Then we can use these methods in the management command.&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># in mail_app\/management\/commands\/send_scheduled_mails.py\n\nfrom datetime import date\n\nfrom django.core.management import BaseCommand\n\nfrom mail_app.models import ScheduledMail\n\nclass Command(BaseCommand):\n\thelp = 'Sends an email to any client for which a discount has started today.'\n\n\tdef handle(self, *args, **options):\n    \ttoday_mail = ScheduledMail.get_today_mail()\n    \tfor mail_message in today_mail:\n        \tmail_message.send_scheduled_mail()<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">Here, to define the from_email argument, we have added value in settings.py. This makes it a bit more modular, but you should then add this variable to the settings file. If not, you can just hardcode a string here. While we\u2019re editing settings though, let\u2019s also add some email parameters. For now, we will just use the file-based email backend so we can test the app.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># in settings.py\n\n...\n# Static files (CSS, JavaScript, Images)\n# https:\/\/docs.djangoproject.com\/en\/3.0\/howto\/static-files\/\n\nSTATIC_URL = '\/static\/'\n\n\n# AUTO_MAIL stuff\n# it doesn't actually matter where this is\n\nEMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'\nEMAIL_FILE_PATH = '\/tmp\/app-messages' # change this to a proper location\n\nAUTO_MAIL_FROM = 'some_mail@mail.com'<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">Neat! Let&#8217;s try it out (you might have to add some objects in admin for it to work)<\/p>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<figure class=\"wp-block-gallery aligncenter has-nested-images columns-default is-cropped wp-block-gallery-2 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image\"><img decoding=\"async\" width=\"1024\" height=\"526\" data-id=\"4474\" src=\"http:\/\/staging.cosmicdevelopment.info\/wp-content\/uploads\/2020\/06\/screenshot_2020-06-02_change_scheduled_mail_django_site_admin-1-1024x526.png\" alt=\"Django for sending scheduled emails with Python programming language\" class=\"wp-image-4474\" srcset=\"https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/screenshot_2020-06-02_change_scheduled_mail_django_site_admin-1-1024x526.png 1024w, https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/screenshot_2020-06-02_change_scheduled_mail_django_site_admin-1-300x154.png 300w, https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/screenshot_2020-06-02_change_scheduled_mail_django_site_admin-1-768x394.png 768w, https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/screenshot_2020-06-02_change_scheduled_mail_django_site_admin-1-1536x788.png 1536w, https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/screenshot_2020-06-02_change_scheduled_mail_django_site_admin-1-370x190.png 370w, https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/screenshot_2020-06-02_change_scheduled_mail_django_site_admin-1-825x423.png 825w, https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/screenshot_2020-06-02_change_scheduled_mail_django_site_admin-1-760x390.png 760w, https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/screenshot_2020-06-02_change_scheduled_mail_django_site_admin-1.png 1853w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/figure>\n\n\n\n<pre class=\"wp-block-code\"><code>$python manage.py send_scheduled_mails\n$cat django_mail\/*.log\n\nContent-Type: text\/html; charset=\"utf-8\"\nMIME-Version: 1.0\nContent-Transfer-Encoding: 7bit\nSubject: My first mail\nFrom: some_mail@mail.com\nTo: TestAccount@mail.com, AnotherTestAccount@mail.com\nDate: Fri, 29 May 2020 11:13:12 -0000\nMessage-ID: &lt;159075079254.4003.12926778827038569342@ninoneutrino&gt;\n\nThis is a simple mail message, uploaded to auto-mail.\nI hope this works!\n\nYours,\nNikola\n\n-------------------------------------------------------------------------------<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">And ta-da! We can send mail via a simple command. This is not the final product yet though \u2013 we will add a bunch of quality of life additions later on (such as a few options when selecting recipients for a new mail, variables within the mail message and so on).<br><\/p>\n\n\n\n<p class=\"has-medium-font-size\">Before we do that though, we have a couple of things to finish off. First off &#8211; the automation. Sending mail via commands is cool, but we can set it up so it&#8217;s all automatic.<br>Enter Cron. Cron is extremely basic, it&#8217;s great for making quick and dirty projects, or demonstrating how to automate something.<br>Just add this to your crontab:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>0 0 * * * cd \/path\/to\/your\/project\/root\/ &amp;&amp; \/path\/to\/your\/venv\/bin\/python3.6 manage.py send_scheduled_mails<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">You can change the minutes and hour values (the first two zeroes) to whatever the current time is + a few minutes, and see if you get anything new in django_mail\/. If it doesn&#8217;t work, check if your paths are correct by executing the command you paster in crontab from your home directory. If there are errors, you can usually find them in \/var\/log\/syslog.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">And as far as automation goes, this is enough. In a more serious project, however, you may want to use Celery, which comes included in the project and will spare you from messing with Cron. Celery is its own beast though, and there&#8217;s little point in writing a tutorial on how to write a celery app when the celery website has its own tutorial, so you might want to check that out at <a rel=\"noreferrer noopener\" aria-label=\"First Steps with Celery (opens in a new tab)\" href=\"https:\/\/docs.celeryproject.org\/en\/stable\/getting-started\/first-steps-with-celery.html\" target=\"_blank\">First Steps with Celery<\/a>  and then later on <a href=\"https:\/\/docs.celeryproject.org\/en\/stable\/django\/first-steps-with-django.html\">First Steps with Django<\/a>.<\/p>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p class=\"has-medium-font-size\">Then, there is one last thing to do &#8211; actually, send emails. So far we&#8217;ve only been saving them in files, but in real life, we want to send real messages, This might be a bit tricky and may involve several other technologies that are out of the scope of this tutorial. If you want to accomplish this, there are a few methods you can think about:<\/p>\n\n\n\n<ul>\n<li>Host your own mail server. If you are doing this as a side project, proof of concept or just messing around, this is probably the way to do it. I recommend either using virtual machines or containers, but the easiest way is to probably use a web solution and just run an AWS or GCE instance.<\/li>\n\n\n\n<li>Use an existing mail server. Gmail, Mailgun, Amazon SES, etc. There&#8217;s a bunch of these, some free, some paid, but in general, you can configure your settings to use a mail server.<\/li>\n<\/ul>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h4 class=\"wp-block-heading\">Short version:&nbsp;<\/h4>\n\n\n\n<p class=\"has-medium-font-size\">So, if you found this and just want to copy and paste some code, here are the final tidbits:&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># models.py\nimport datetime\nfrom datetime import date\n\nfrom django.db import models\nfrom django.utils import timezone\nfrom django.core.mail import EmailMessage\n\nfrom django.conf import settings\n\nauto_mail_from = 'from@mail.com'\nif hasattr(settings, 'AUTO_MAIL_FROM'):\n\tauto_mail_info = settings.AUTO_MAIL_FROM\n\nclass MailAttachment(models.Model):\n\tattachment_file = models.FileField()\n\tattached_to = models.ForeignKey('ScheduledMail', related_name = 'attachments', on_delete = models.CASCADE)\n\n\tdef __str__(self):\n    \treturn '%s (%s)' % (self.attachment_file.filename, self.attached_to.subject)\n\nclass MailRecipient(models.Model):\n\tmail_address = models.CharField(max_length = 40)\n\n\tdef __str__(self):\n    \treturn self.mail_address\n\nclass ScheduledMail(models.Model):\n\tsubject = models.CharField(max_length = 40)\n\ttemplate = models.FileField(upload_to = 'mail_app\/mails')\n\tsend_on = models.DateTimeField(default = timezone.now())\n\trecipients_list = models.ManyToManyField(MailRecipient, related_name = 'mail_list')\n\n\tdef __str__(self):\n    \treturn self.subject\n\n\t@classmethod\n\tdef get_today_mail(cls):\n    \ttoday = date.today()\n    \treturn cls.objects.filter(send_on__year = today.year, send_on__month = today.month, send_on__day = today.day)\n\n\tdef send_scheduled_mail(self):\n    \tmessage = self.template.read().decode('utf-8')\n    \trecipient_list = list(self.recipients_list.values_list('mail_address', flat = True))\n    \tmail_msg = EmailMessage(\n        \tsubject = self.subject,\n        \tbody = message,\n        \tfrom_email = auto_mail_from,\n        \tto = recipient_list,\n    \t)\n    \tmail_msg.content_subtype = 'html'\n   \t \n    \tmail_msg.send()<\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<pre class=\"wp-block-code\"><code># admin.py\nfrom django.contrib import admin\nfrom .models import ScheduledMail, MailAttachment, MailRecipient\n\n# Register your models here.\n\n@admin.register(ScheduledMail)\nclass MailAdmin(admin.ModelAdmin):\n\tpass\n\n@admin.register(MailAttachment)\nclass AttachmentAdmin(admin.ModelAdmin):\n\tpass\n\n@admin.register(MailRecipient)\nclass RecipientAdmin(admin.ModelAdmin):\n\tpass<\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<pre class=\"wp-block-code\"><code>#management\/commands\/send_scheduled_mail.py\nimport datetime\n\nfrom django.core.management import BaseCommand\n\nfrom mail_app.models import ScheduledMail\n\nclass Command(BaseCommand):\n\thelp = 'Sends an email to any client for which a discount has started today.'\n\n\tdef handle(self, *args, **options):\n    \ttoday_mail = ScheduledMail.get_today_mail()\n    \tfor mail_message in today_mail:\n        \tmail_message.send_scheduled_mail()<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\"> And you put this in your crontab:&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>0 0 * * * cd \/path\/to\/project\/ &amp;&amp; \/path\/to\/venv\/bin\/python3.6 manage.py send_scheduled_mails<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">Then set up your mail server in your settings.py!&nbsp;<br>To make it easier, I have packaged the app, so you can install it via pip. Here is the package: <\/p>\n\n\n\n<div class=\"wp-block-file\"><a id=\"wp-block-file--media-1d74e812-2b91-4690-b712-ee10243b383f\" href=\"https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/mail_app-0.1.tar.gz\" target=\"_blank\" rel=\"noreferrer noopener\">mail_app-0.1.tar<\/a><a href=\"https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/mail_app-0.1.tar.gz\" class=\"wp-block-file__button wp-element-button\" download aria-describedby=\"wp-block-file--media-1d74e812-2b91-4690-b712-ee10243b383f\">Download<\/a><\/div>\n\n\n\n<p class=\"has-medium-font-size\">You can install it via <code>python -m pip install mail_app-0.1.tar.gz<\/code><\/p>\n\n\n\n<p class=\"has-medium-font-size\">You can use the management command as described above. In order to do so, however, you still have to add it to INSTALLED_APPS in the settings.py file, as well as define MEDIA_ROOT and MEDIA_URL settings values.&nbsp;<\/p>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>NOTE<\/strong>:<\/h4>\n\n\n\n<p class=\"has-medium-font-size\">I have to warn you, if you are just copy-pasting this code in your app, \u2013 I have some values in settings.py which should probably not be used in production. Namely:<br><\/p>\n\n\n\n<ul>\n<li> Debug is on<\/li>\n\n\n\n<li> Database is sqlite3<\/li>\n\n\n\n<li> Allowed hosts is <code>'*'<\/code><\/li>\n<\/ul>\n\n\n\n<p class=\"has-medium-font-size\">All of these are just to make the presentation easier. In a production environment, you definitely want to debug off, a more stable database, and stricter allowed hosts. So there, you have been warned.<br><\/p>\n\n\n\n<p class=\"has-medium-font-size\"><em>Was this the solution you needed? If yes, send us a message to explain the process you went through when discovering how to send scheduled emails with Python. If you need more help, please let us know by getting a <\/em><a href=\"https:\/\/www.cosmicdevelopment.com\/hire-us\/\"><em>free consultation<\/em><\/a><em> with our experts.<br><\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>By Nikola Dokoski Witnessing the rise of Python, we can&#8217;t help but notice its implementation in almost every aspect of our lives. From its general purpose for developing GUI applications, web applications, and websites, to its core functionality, which is to take care of the common programming tasks, Python is certainly classified as a high-level programming language. With that being&hellip;<\/p>\n","protected":false},"author":12,"featured_media":6124,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"editor_plus_copied_stylings":"{}","_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[638],"tags":[52,53,198,230,231],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v22.2 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>How to Send Scheduled Emails with Python | Cosmic Development<\/title>\n<meta name=\"description\" content=\"Do you use Python programming language to send scheduled emails? Learn how to send scheduled emails with Python from our Python expert Nikola Dokoski.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Send Scheduled Emails with Python | Cosmic Development\" \/>\n<meta property=\"og:description\" content=\"Do you use Python programming language to send scheduled emails? Learn how to send scheduled emails with Python from our Python expert Nikola Dokoski.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/\" \/>\n<meta property=\"og:site_name\" content=\"Cosmic Development\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/cosmicdevelopment\/\" \/>\n<meta property=\"article:published_time\" content=\"2020-06-04T10:22:12+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-01-22T14:57:33+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/mobile-phone-1513945_1920-1.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1920\" \/>\n\t<meta property=\"og:image:height\" content=\"1431\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Viktorija Nikoloska\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@cosmicdevelopment\" \/>\n<meta name=\"twitter:site\" content=\"@cosmicdevelopment\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Viktorija Nikoloska\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/\"},\"author\":{\"name\":\"Viktorija Nikoloska\",\"@id\":\"https:\/\/www.cosmicdevelopment.com\/#\/schema\/person\/7316e414960654a00f80511be0074803\"},\"headline\":\"How to Send Scheduled Emails with Python\",\"datePublished\":\"2020-06-04T10:22:12+00:00\",\"dateModified\":\"2024-01-22T14:57:33+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/\"},\"wordCount\":1358,\"commentCount\":153,\"publisher\":{\"@id\":\"https:\/\/www.cosmicdevelopment.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/mobile-phone-1513945_1920-1.jpg\",\"keywords\":[\"django\",\"python\",\"Python Programming Language\",\"How to Send Scheduled Emails with Python\",\"Send Scheduled Emails\"],\"articleSection\":[\"Outstaffing and Tech Insights\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/\",\"url\":\"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/\",\"name\":\"How to Send Scheduled Emails with Python | Cosmic Development\",\"isPartOf\":{\"@id\":\"https:\/\/www.cosmicdevelopment.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/mobile-phone-1513945_1920-1.jpg\",\"datePublished\":\"2020-06-04T10:22:12+00:00\",\"dateModified\":\"2024-01-22T14:57:33+00:00\",\"description\":\"Do you use Python programming language to send scheduled emails? Learn how to send scheduled emails with Python from our Python expert Nikola Dokoski.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/#primaryimage\",\"url\":\"https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/mobile-phone-1513945_1920-1.jpg\",\"contentUrl\":\"https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/mobile-phone-1513945_1920-1.jpg\",\"width\":1920,\"height\":1431},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.cosmicdevelopment.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to Send Scheduled Emails with Python\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.cosmicdevelopment.com\/#website\",\"url\":\"https:\/\/www.cosmicdevelopment.com\/\",\"name\":\"Cosmic Development\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/www.cosmicdevelopment.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.cosmicdevelopment.com\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.cosmicdevelopment.com\/#organization\",\"name\":\"Cosmic Development\",\"url\":\"https:\/\/www.cosmicdevelopment.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.cosmicdevelopment.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2023\/12\/cropped-favicon.png\",\"contentUrl\":\"https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2023\/12\/cropped-favicon.png\",\"width\":512,\"height\":512,\"caption\":\"Cosmic Development\"},\"image\":{\"@id\":\"https:\/\/www.cosmicdevelopment.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/cosmicdevelopment\/\",\"https:\/\/twitter.com\/cosmicdevelopment\",\"https:\/\/www.instagram.com\/cosmicdevelopment\/\",\"https:\/\/rumble.com\/user\/CosmicDevelopment\",\"https:\/\/www.linkedin.com\/company\/cosmic-development\/mycompany\/verification\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.cosmicdevelopment.com\/#\/schema\/person\/7316e414960654a00f80511be0074803\",\"name\":\"Viktorija Nikoloska\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.cosmicdevelopment.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/d1f22952dc7d3fb45664d3d116dcc8e1?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/d1f22952dc7d3fb45664d3d116dcc8e1?s=96&d=mm&r=g\",\"caption\":\"Viktorija Nikoloska\"},\"sameAs\":[\"https:\/\/mk.linkedin.com\/in\/viktorijanikoloska\"],\"url\":\"https:\/\/www.cosmicdevelopment.com\/author\/viktorija-nikoloska\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"How to Send Scheduled Emails with Python | Cosmic Development","description":"Do you use Python programming language to send scheduled emails? Learn how to send scheduled emails with Python from our Python expert Nikola Dokoski.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/","og_locale":"en_US","og_type":"article","og_title":"How to Send Scheduled Emails with Python | Cosmic Development","og_description":"Do you use Python programming language to send scheduled emails? Learn how to send scheduled emails with Python from our Python expert Nikola Dokoski.","og_url":"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/","og_site_name":"Cosmic Development","article_publisher":"https:\/\/www.facebook.com\/cosmicdevelopment\/","article_published_time":"2020-06-04T10:22:12+00:00","article_modified_time":"2024-01-22T14:57:33+00:00","og_image":[{"width":1920,"height":1431,"url":"https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/mobile-phone-1513945_1920-1.jpg","type":"image\/jpeg"}],"author":"Viktorija Nikoloska","twitter_card":"summary_large_image","twitter_creator":"@cosmicdevelopment","twitter_site":"@cosmicdevelopment","twitter_misc":{"Written by":"Viktorija Nikoloska","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/#article","isPartOf":{"@id":"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/"},"author":{"name":"Viktorija Nikoloska","@id":"https:\/\/www.cosmicdevelopment.com\/#\/schema\/person\/7316e414960654a00f80511be0074803"},"headline":"How to Send Scheduled Emails with Python","datePublished":"2020-06-04T10:22:12+00:00","dateModified":"2024-01-22T14:57:33+00:00","mainEntityOfPage":{"@id":"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/"},"wordCount":1358,"commentCount":153,"publisher":{"@id":"https:\/\/www.cosmicdevelopment.com\/#organization"},"image":{"@id":"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/#primaryimage"},"thumbnailUrl":"https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/mobile-phone-1513945_1920-1.jpg","keywords":["django","python","Python Programming Language","How to Send Scheduled Emails with Python","Send Scheduled Emails"],"articleSection":["Outstaffing and Tech Insights"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/","url":"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/","name":"How to Send Scheduled Emails with Python | Cosmic Development","isPartOf":{"@id":"https:\/\/www.cosmicdevelopment.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/#primaryimage"},"image":{"@id":"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/#primaryimage"},"thumbnailUrl":"https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/mobile-phone-1513945_1920-1.jpg","datePublished":"2020-06-04T10:22:12+00:00","dateModified":"2024-01-22T14:57:33+00:00","description":"Do you use Python programming language to send scheduled emails? Learn how to send scheduled emails with Python from our Python expert Nikola Dokoski.","breadcrumb":{"@id":"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/#primaryimage","url":"https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/mobile-phone-1513945_1920-1.jpg","contentUrl":"https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2020\/06\/mobile-phone-1513945_1920-1.jpg","width":1920,"height":1431},{"@type":"BreadcrumbList","@id":"https:\/\/www.cosmicdevelopment.com\/how-to-send-scheduled-emails-with-the-programming-language-python\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.cosmicdevelopment.com\/"},{"@type":"ListItem","position":2,"name":"How to Send Scheduled Emails with Python"}]},{"@type":"WebSite","@id":"https:\/\/www.cosmicdevelopment.com\/#website","url":"https:\/\/www.cosmicdevelopment.com\/","name":"Cosmic Development","description":"","publisher":{"@id":"https:\/\/www.cosmicdevelopment.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.cosmicdevelopment.com\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.cosmicdevelopment.com\/#organization","name":"Cosmic Development","url":"https:\/\/www.cosmicdevelopment.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.cosmicdevelopment.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2023\/12\/cropped-favicon.png","contentUrl":"https:\/\/www.cosmicdevelopment.com\/wp-content\/uploads\/2023\/12\/cropped-favicon.png","width":512,"height":512,"caption":"Cosmic Development"},"image":{"@id":"https:\/\/www.cosmicdevelopment.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/cosmicdevelopment\/","https:\/\/twitter.com\/cosmicdevelopment","https:\/\/www.instagram.com\/cosmicdevelopment\/","https:\/\/rumble.com\/user\/CosmicDevelopment","https:\/\/www.linkedin.com\/company\/cosmic-development\/mycompany\/verification\/"]},{"@type":"Person","@id":"https:\/\/www.cosmicdevelopment.com\/#\/schema\/person\/7316e414960654a00f80511be0074803","name":"Viktorija Nikoloska","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.cosmicdevelopment.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/d1f22952dc7d3fb45664d3d116dcc8e1?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d1f22952dc7d3fb45664d3d116dcc8e1?s=96&d=mm&r=g","caption":"Viktorija Nikoloska"},"sameAs":["https:\/\/mk.linkedin.com\/in\/viktorijanikoloska"],"url":"https:\/\/www.cosmicdevelopment.com\/author\/viktorija-nikoloska\/"}]}},"_links":{"self":[{"href":"https:\/\/www.cosmicdevelopment.com\/wp-json\/wp\/v2\/posts\/4422"}],"collection":[{"href":"https:\/\/www.cosmicdevelopment.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cosmicdevelopment.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cosmicdevelopment.com\/wp-json\/wp\/v2\/users\/12"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cosmicdevelopment.com\/wp-json\/wp\/v2\/comments?post=4422"}],"version-history":[{"count":1,"href":"https:\/\/www.cosmicdevelopment.com\/wp-json\/wp\/v2\/posts\/4422\/revisions"}],"predecessor-version":[{"id":11470,"href":"https:\/\/www.cosmicdevelopment.com\/wp-json\/wp\/v2\/posts\/4422\/revisions\/11470"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.cosmicdevelopment.com\/wp-json\/wp\/v2\/media\/6124"}],"wp:attachment":[{"href":"https:\/\/www.cosmicdevelopment.com\/wp-json\/wp\/v2\/media?parent=4422"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cosmicdevelopment.com\/wp-json\/wp\/v2\/categories?post=4422"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cosmicdevelopment.com\/wp-json\/wp\/v2\/tags?post=4422"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}