aboutsummaryrefslogtreecommitdiff
path: root/blog/2022-06-22-daily-poetry.org
diff options
context:
space:
mode:
Diffstat (limited to 'blog/2022-06-22-daily-poetry.org')
-rw-r--r--blog/2022-06-22-daily-poetry.org254
1 files changed, 140 insertions, 114 deletions
diff --git a/blog/2022-06-22-daily-poetry.org b/blog/2022-06-22-daily-poetry.org
index 37a9e0b..dd1e249 100644
--- a/blog/2022-06-22-daily-poetry.org
+++ b/blog/2022-06-22-daily-poetry.org
@@ -1,71 +1,80 @@
-+++
-date = 2022-06-22
-title = "Daily Plaintext Poetry via Email"
-description = "A quick tutorial showing how to use Python and the PoetryDB API to email daily poetry."
-draft = false
-+++
-
-## Source Code
-
-I don't want to bury the lede here, so if you'd like to see the full source
-code I use to email myself plaintext poems daily, visit the repository:
-[daily-poem](https://git.sr.ht/~cmc/daily-poem/).
-
-## My Daily Dose of Poetry
-
-Most of my programming projects are small, random projects that are made
+#+title: Daily Plaintext Poetry via Email
+#+date: 2022-06-22
+
+** Source Code
+:PROPERTIES:
+:CUSTOM_ID: source-code
+:END:
+I don't want to bury the lede here, so if you'd like to see the full
+source code I use to email myself plaintext poems daily, visit the
+repository: [[https://git.sr.ht/~cmc/daily-poem/][daily-poem]].
+
+** My Daily Dose of Poetry
+:PROPERTIES:
+:CUSTOM_ID: my-daily-dose-of-poetry
+:END:
+Most of my programming projects are small, random projects that are made
strictly to fix some small problem I have or enhance my quality of life.
-In this case, I was looking for a simply and easy way to get a daily dose of
-literature or poetry to read in the mornings.
-
-However, I don't want to sign up for a random mailing list on just any website.
-I also don't want to have to work to find the reading content each morning, as I
-know I would simply give up and stop reading daily.
+In this case, I was looking for a simply and easy way to get a daily
+dose of literature or poetry to read in the mornings.
-Thus, I found a way to deliver poetry to myself in plain-text format, on a daily
-basis, and scheduled to deliver automatically.
+However, I don't want to sign up for a random mailing list on just any
+website. I also don't want to have to work to find the reading content
+each morning, as I know I would simply give up and stop reading daily.
-## Prerequisites
+Thus, I found a way to deliver poetry to myself in plain-text format, on
+a daily basis, and scheduled to deliver automatically.
-This solution uses Python and email, so the following process requires the
-following to be installed:
+** Prerequisites
+:PROPERTIES:
+:CUSTOM_ID: prerequisites
+:END:
+This solution uses Python and email, so the following process requires
+the following to be installed:
-1. An SMTP server, which can be as easy as installing `mailutils` if you're on
-a Debian-based distro.
+1. An SMTP server, which can be as easy as installing =mailutils= if
+ you're on a Debian-based distro.
2. Python (& pip!)
-3. The following Python packages: `email`, `smtplib`, `json`, and `requests`
-
-## Breaking Down the Logic
-
-I want to break down the logic for this program, as it's quite simple and
-informational.
-
-### Required Packages
-
-This program starts with a simple import of the required packages, so I wanted
-to explain why each package is used:
-
-```py
+3. The following Python packages: =email=, =smtplib=, =json=, and
+ =requests=
+
+** Breaking Down the Logic
+:PROPERTIES:
+:CUSTOM_ID: breaking-down-the-logic
+:END:
+I want to break down the logic for this program, as it's quite simple
+and informational.
+
+*** Required Packages
+:PROPERTIES:
+:CUSTOM_ID: required-packages
+:END:
+This program starts with a simple import of the required packages, so I
+wanted to explain why each package is used:
+
+#+begin_src py
from email.mime.text import MIMEText # Required for translating MIMEText
import smtplib # Required to process the SMTP mail delivery
import json # Required to parse the poetry API results
import requests # Required to send out a request to the API
-```
-
-### Sending the API Request
+#+end_src
-Next, we need to actually send the API request. In my case, I'm calling a random
-poem from the entire API. If you want, you can call specific poems or authors
-from this API.
+*** Sending the API Request
+:PROPERTIES:
+:CUSTOM_ID: sending-the-api-request
+:END:
+Next, we need to actually send the API request. In my case, I'm calling
+a random poem from the entire API. If you want, you can call specific
+poems or authors from this API.
-```py
+#+begin_src py
json_data = requests.get('https://poetrydb.org/random').json()
-```
+#+end_src
This gives us the following result in JSON:
-```json
+#+begin_src json
[
{
"title": "Sonnet XXII: With Fools and Children",
@@ -91,80 +100,95 @@ This gives us the following result in JSON:
"linecount": "15"
}
]
-```
-
-### Parsing the API Results
-
-In order to parse this into a readable format, we need to use the `json` package
-and extract the fields we want. In the example below, I am grabbing every field
-presented by the API.
-
-For the actual poem content, we need to loop over each line in the `lines`
-variable since each line is a separate string by default.
-
-> You *could* also extract the title or author and make another call out to the
-> API to avoid having to build the plaintext poem with a loop, but it just
-> doesn't make sense to me to send multiple requests when we can create a simple
-> loop on our local machine to work with the data we already have.
->
-> For
-> [example](https://poetrydb.org/title/Sonnet%20XXII:%20With%20Fools%20and%20Children/lines.text),
-> look at the raw data response of this link to see the poem's lines returned
-> in plaintext.
-
-```py
+#+end_src
+
+*** Parsing the API Results
+:PROPERTIES:
+:CUSTOM_ID: parsing-the-api-results
+:END:
+In order to parse this into a readable format, we need to use the =json=
+package and extract the fields we want. In the example below, I am
+grabbing every field presented by the API.
+
+For the actual poem content, we need to loop over each line in the
+=lines= variable since each line is a separate string by default.
+
+#+begin_quote
+You /could/ also extract the title or author and make another call out
+to the API to avoid having to build the plaintext poem with a loop, but
+it just doesn't make sense to me to send multiple requests when we can
+create a simple loop on our local machine to work with the data we
+already have.
+
+For
+[[https://poetrydb.org/title/Sonnet%20XXII:%20With%20Fools%20and%20Children/lines.text][example]],
+look at the raw data response of this link to see the poem's lines
+returned in plaintext.
+
+#+end_quote
+
+#+begin_src py
title = json_data[0]['title']
author = json_data[0]['author']
line_count = json_data[0]['linecount']
lines = ''
for line in json_data[0]['lines']:
lines = lines + line + "\n"
-```
-
-### Composing the Email
+#+end_src
-Now that I have all the data I need, I just need to compose it into a message
-and prepare the message metadata.
+*** Composing the Email
+:PROPERTIES:
+:CUSTOM_ID: composing-the-email
+:END:
+Now that I have all the data I need, I just need to compose it into a
+message and prepare the message metadata.
-For my daily email, I want to see the title of the poem first, followed by the
-author, then a blank line, and finally the full poem. This code snippet combines
-that data and packages it into a MIMEText container, ready to be emailed.
+For my daily email, I want to see the title of the poem first, followed
+by the author, then a blank line, and finally the full poem. This code
+snippet combines that data and packages it into a MIMEText container,
+ready to be emailed.
-```py
+#+begin_src py
msg_body = title + "\n" + author + "\n\n" + lines
msg = MIMEText(msg_body)
-```
+#+end_src
-Before we send the email, we need to prepare the metadata (subject, from, to,
-etc.):
+Before we send the email, we need to prepare the metadata (subject,
+from, to, etc.):
-```py
+#+begin_src py
sender_email = 'example@server.local'
recipient_emails = ['user@example.com']
msg['Subject'] = 'Your Daily Poem (' + line_count + ' lines)'
msg['From'] = sender_email
msg['To'] = recipient_email
-```
-
-### Sending the Email
-
-Now that I have everything ready to be emailed, the last step is to simply
-connect to an SMTP server and send the email out to the recipients. In my case,
-I installed `mailutils` on Ubuntu and let my SMTP server be `localhost`.
-
-```py
+#+end_src
+
+*** Sending the Email
+:PROPERTIES:
+:CUSTOM_ID: sending-the-email
+:END:
+Now that I have everything ready to be emailed, the last step is to
+simply connect to an SMTP server and send the email out to the
+recipients. In my case, I installed =mailutils= on Ubuntu and let my
+SMTP server be =localhost=.
+
+#+begin_src py
smtp_server = 'localhost'
s = smtplib.SMTP(smtp_server)
s.sendmail(sender_email, recipient_emails, msg.as_string())
s.quit()
-```
+#+end_src
-## The Result!
+** The Result!
+:PROPERTIES:
+:CUSTOM_ID: the-result
+:END:
+Instead of including a screenshot, I've copied the contents of the email
+that was delivered to my inbox below since I set this process up in
+plaintext format.
-Instead of including a screenshot, I've copied the contents of the email that
-was delivered to my inbox below since I set this process up in plaintext format.
-
-```txt
+#+begin_src txt
Date: Wed, 22 Jun 2022 14:37:19 +0000 (UTC)
From: REDACTED
To: REDACTED
@@ -190,24 +214,26 @@ You that behold us, laugh us not to scorn;
Give Nature thanks you are not such as we.
Yet fools and children sometimes tell in play
Some, wise in show, more fools indeed than they.
-```
-
-## Scheduling the Daily Email
+#+end_src
-Last, but not least, is scheduling this Python script with `crontab`. To
-schedule a script to run daily, you can add it to the `crontab` file. To do
-this, open `crontab` in editing mode:
+** Scheduling the Daily Email
+:PROPERTIES:
+:CUSTOM_ID: scheduling-the-daily-email
+:END:
+Last, but not least, is scheduling this Python script with =crontab=. To
+schedule a script to run daily, you can add it to the =crontab= file. To
+do this, open =crontab= in editing mode:
-```sh
+#+begin_src sh
crontab -e
-```
+#+end_src
-In the file, simply paste the following snippet at the bottom of the file and
-ensure that the file path is correctly pointing to wherever you saved your
-Python script:
+In the file, simply paste the following snippet at the bottom of the
+file and ensure that the file path is correctly pointing to wherever you
+saved your Python script:
-```config
+#+begin_src config
0 8 * * * python3 /home/<your_user>/dailypoem/main.py
-```
+#+end_src
We have now set up the script and scheduled it to run daily at 08:00!