aboutsummaryrefslogtreecommitdiff
path: root/blog/daily-poetry
diff options
context:
space:
mode:
authorChristian Cleberg <hello@cleberg.net>2024-03-04 22:34:28 -0600
committerChristian Cleberg <hello@cleberg.net>2024-03-04 22:34:28 -0600
commit797a1404213173791a5f4126a77ad383ceb00064 (patch)
treefcbb56dc023c1e490df70478e696041c566e58b4 /blog/daily-poetry
parent3db79e7bb6a34ee94935c22d7f0e18cf227c7813 (diff)
downloadcleberg.net-797a1404213173791a5f4126a77ad383ceb00064.tar.gz
cleberg.net-797a1404213173791a5f4126a77ad383ceb00064.tar.bz2
cleberg.net-797a1404213173791a5f4126a77ad383ceb00064.zip
initial migration to test org-mode
Diffstat (limited to 'blog/daily-poetry')
-rw-r--r--blog/daily-poetry/index.org208
1 files changed, 208 insertions, 0 deletions
diff --git a/blog/daily-poetry/index.org b/blog/daily-poetry/index.org
new file mode 100644
index 0000000..e150c8b
--- /dev/null
+++ b/blog/daily-poetry/index.org
@@ -0,0 +1,208 @@
+#+title: Daily Plaintext Poetry via Email
+#+date: 2022-06-22
+#+description: A small project to automatically deliver poetry to your inbox daily.
+#+filetags: :selfhosting:
+
+* 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: [[https://git.cleberg.net/daily-poem.git][daily-poem.git]].
+
+* My Daily Dose of Poetry
+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.
+
+Thus, I found a way to deliver poetry to myself in plain-text format, on
+a daily basis, and scheduled to deliver automatically.
+
+* Prerequisites
+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.
+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:
+
+#+begin_src python
+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
+#+end_src
+
+** Sending the API Request
+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.
+
+#+begin_src python
+json_data = requests.get('https://poetrydb.org/random').json()
+#+end_src
+
+This gives us the following result in JSON:
+
+#+begin_src json
+[
+ {
+ "title": "Sonnet XXII: With Fools and Children",
+ "author": "Michael Drayton",
+ "lines": [
+ "To Folly",
+ "",
+ "With fools and children, good discretion bears;",
+ "Then, honest people, bear with Love and me,",
+ "Nor older yet, nor wiser made by years,",
+ "Amongst the rest of fools and children be;",
+ "Love, still a baby, plays with gauds and toys,",
+ "And, like a wanton, sports with every feather,",
+ "And idiots still are running after boys,",
+ "Then fools and children fitt'st to go together.",
+ "He still as young as when he first was born,",
+ "No wiser I than when as young as he;",
+ "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."
+ ],
+ "linecount": "15"
+ }
+]
+#+end_src
+
+** 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.
+
+#+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 python
+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"
+#+end_src
+
+** Composing the Email
+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.
+
+#+begin_src python
+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.):
+
+#+begin_src python
+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
+#+end_src
+
+** 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=.
+
+#+begin_src python
+smtp_server = 'localhost'
+s = smtplib.SMTP(smtp_server)
+s.sendmail(sender_email, recipient_emails, msg.as_string())
+s.quit()
+#+end_src
+
+* The Result!
+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.
+
+#+begin_src txt
+Date: Wed, 22 Jun 2022 14:37:19 +0000 (UTC)
+From: REDACTED
+To: REDACTED
+Subject: Your Daily Poem (36 lines)
+MIME-Version: 1.0
+Content-Transfer-Encoding: 8bit
+Content-Type: text/plain; charset=utf-8
+
+Sonnet XXII: With Fools and Children
+Michael Drayton
+
+With fools and children, good discretion bears;
+Then, honest people, bear with Love and me,
+Nor older yet, nor wiser made by years,
+Amongst the rest of fools and children be;
+Love, still a baby, plays with gauds and toys,
+And, like a wanton, sports with every feather,
+And idiots still are running after boys,
+Then fools and children fitt'st to go together.
+He still as young as when he first was born,
+No wiser I than when as young as he;
+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.
+#+end_src
+
+* Scheduling the Daily Email
+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:
+
+#+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:
+
+#+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!