#!/bin/sh
from="John Doe <john.doe@email.com>"
subject="$1"
echo | mail -r "$from" -s "$subject" "$from"
2023-02-10
Since I cannot keep everything I have to remember in my head, I need a reminder system. While I would prefer an analog system (ideally one that integrates with my system for keeping track of tasks), I have not found a satisfying analog solution so far.
I am not looking for a full-fledged calendar system. If I were, I would be using Remind or `calendar`[1]. But they offer way more features than I need.
I basically have two requirements for my reminder system:
It has to remind me reliably by e-mail about things a certain time in advance.
It has to be simple and have as few external dependencies as possible.
The solution I have come up with is almost too trivial to share: It employs
cron
and at
to schedule reminders, which are sent as e-mails via a remote
SMTP server when they are due.
The system depends on the following ingredients:
A machine which is up 24/7 – for scheduling reminders for arbitrary times.[2] I am using a server hosted on OpenBSD Amsterdam.
smtpd
– for relaying e-mails to a remote SMTP
server.
cron
– for scheduling recurring reminders (like birthdays).
at
– for scheduling nonrecurring reminders (like one-time events, or
events which recur in irregular intervals).
mail
– for sending e-mails non-interactively.
On OpenBSD, all the required software is part of the base system; see smtpd(8), cron(8), at(1), mail(1).
Both cron
and at
basically take two kinds of data as input: A timestamp
which specifies when something is to be done, and an action which specifies
what is to be done at the specified time.
Regardless of whether a reminder is recurring or nonrecurring, I want an e-mail
to be sent to me at the specified time. Therefore, the action in both cases is
sending an e-mail to me reminding me of the given event. Since the e-mail needs
to be sent non-interactively when the given time is reached, the mail
utility
is invoked, and the reminder text is passed to it as the mail subject (since
they are usually short, I only specify a subject and leave the body empty; then
I don’t even have to open the e-mail).
In order not to have to specify the non-changing details (like the e-mail
address) for sending the mail each time, I employ a small script called
mailrem
which is basically a wrapper around mail
which takes the reminder
text as its argument:
#!/bin/sh
from="John Doe <john.doe@email.com>"
subject="$1"
echo | mail -r "$from" -s "$subject" "$from"
Finally, in order for mail
to be able to send mails to a remote SMTP server,
smtpd
needs to be configured such that it relays outgoing
mail to a remote server.
E-mail reminders are sent by calling mailrem
with the specific reminder text
as its argument, e.g.
$ mailrem "Prepare tax statement"
In order to schedule reminders for a specific time, mailrem
is not invoked
directly as above, but either by cron
or by at
, depending on whether the
reminder is to be sent on a regular basis or just once.
Recurring reminders are scheduled by cron
via corresponding crontab entries.
Start editing the crontab file:
$ crontab -e
Then add an entry for each recurring reminder like this:
0 0 3 18 * $HOME/bin/mailrem "[Reminder] Paul's $(( $(/bin/date +\%Y) - 1976 )). birthday (1976)"
This entry would send an e-mail each year at midnight on March 18 with subject
“[Reminder] Paul’s n. birthday (1976)”, where n is calculated each time
the cron entry is triggered by subtracting Paul’s year of birth, 1976, from the
current year obtained by the date
utility[3].
Nonrecurring reminders are scheduled by at
via corresponding atjobs. For
instance, to schedule an atjob for midnight in three days:
$ at midnight + 3 days
When prompted, enter the action to be executed at the specified time like this:
> mailrem "[Reminder] Doctor's appointment at 9 am"
Then, press Ctrl + D
to queue the atjob.
That’s it. A very simple system which does its job and is easy to setup and maintain.
The system is certainly not suitable for time-critical reminders. This is obvious, since by nature the reminders are sent in an asynchroneous way (i.e. via e-mail).
There is no easy way to get a consolidated overview over all currently
scheduled reminders. For recurring reminders, crontab -l
could be used.
Similarly, atq
displays the queue of atjobs. However, the output of atq
is
pretty much unparseable (at least in the version which ships with OpenBSD). So
one would have to manually extract the job ID from the output of atq
and
then do $ at -c <id>
in order to see the content of the job.
Failures cannot easily be discovered in general, and there is no recovery
mechanism. If, e.g., for some reason the cron
daemon is not running at the
time a reminder is due, it will not be sent and will subsequently be lost
forever.