As a lower-mid-tier nerd, I’m just nerdy enough to be running a home media server (old Dell box, on Ubuntu 20, with Plex and nothing else). I also own my own domain (hey, you’re on it!), which gives me the power to create a nigh-infinite number of email addresses.
This, in turn, lets me make a generic email for all the sign-up garbage I need to use once and never again. “Enter your email / click the link in your email to register for | download | access” stuff.
What I wanted to do was have all that stuff funnel into a box that self-deletes every night. Get the confirmation email, click the thing, and nope out, knowing that any junk mail or follow-ups will auto-clear.
Since I have the local computer running (close to) 24/7 as a media server, and Ubuntu, and my own mailbox, why not dive into the wonderful world of Python scripts and cron jobs to make it happen?
(For the record, this seems like a jovial public-facing post, but it’s really just for me so I can remember how to do this stuff if I need to do it again).
Here’s the script, courtesy of the good people at Opalstack, my web host. Nice, responsive, and ultimately patient people!
#!usr/local/bin/python3
import imaplib
import ssl
from datetime import datetime
# your IMAP server credentials
IMAP_HOST = 'mail.us.opalstack.com'
IMAP_USER = 'user'
IMAP_PASS = 'password'
def clear_old_messages():
today = datetime.today().strftime('%d-%b-%Y')
ctx = ssl.create_default_context()
server = imaplib.IMAP4_SSL(host=IMAP_HOST, ssl_context=ctx)
server.login(IMAP_USER, IMAP_PASS)
server.select()
resp, items = server.search(None, f"SENTBEFORE {today}")
#resp, items = server.search(None, "SENTBEFORE {}" .format(today)) [[python 3.5]]
items = items[0].split()
for i in items:
server.store(i, '+FLAGS', '\\Deleted')
server.expunge()
server.logout()
if __name__ == '__main__':
clear_old_messages()
I save the script as garbage.py in a folder called “scripts” in my home folder, and make it executable:
chmod u+x garbage.py
On the Ubuntu server, I open up the crontab editor with
crontab -e
Then adding at the bottom of the crontab
0 1 * * * /home/[user]/scripts/garbage.py
I made an earlier mistake setting this up with a relative file path
0 1 * * * ~/scripts/garbage.py
but that was a no-go for some reason. Using the absolute path helped the cron job find the script and run it.
When that didn’t work, I got advised that putting the path in the cron job as well as the shebang will bulletproof it more:
0 1 * * * /usr/bin/python3 /home/[user]/scripts/garbage.py > /home/[user]/logs/garbage.log 2>&1
Things that have gone wrong
- Including the path to Python in the crontab. I was pushing the crontab just to the script and assuming the shebang to Python would be enough — apparently not (I’ve updated the post above).
- Permission Denied for the path to the Python script. I’m finding the Python script using whereis python and locating it at /usr/lib/python3.8, but the crontab log is giving me a “Permission Denied” in the log. The solve there was using usr/bin/python3.8 — no idea why lib is permission denied and bin is okay, but whatever works, works. I’ve updated the post above.
- When Python updates, the path breaks — I had crontab calling /usr/lib/python3.7 and getting a not found error, which was vexing until I realized Python had updated to 3.8 and I hadn’t noticed. This applies to both the shebang for the script and the crontab call. The fix: you can call the Python version (python3) without the subversion (python3.8) — but not just “python”, because then the system calls Python 2, which can’t run the script. Once again, the post above’s been updated.
- Moved everything to a Synology server, and while its built-in task scheduler has solved the cron job for me, after a ton of syntax errors I finally discovered that the above script uses an f-string that only works in Python 3.6+, and the Python 3 module in the Synology package manager only supports 3.5.1. So the script above has been amended again to reflect that.