Send a command for each email you receive. Like crontab, with IMAP

boyska 4dea8fd240 allow passwords to be saved on an external file 5 years ago
cmd d3fcf0aa8e better check db config 5 years ago
.gitignore f595f36840 ignore db 5 years ago
README.md 4dea8fd240 allow passwords to be saved on an external file 5 years ago
action.go 9086cb593e add MESSAGEID to env 5 years ago
config.go 4dea8fd240 allow passwords to be saved on an external file 5 years ago
imap.go 4dea8fd240 allow passwords to be saved on an external file 5 years ago
time.go 3330a7b342 run commands! "since" config key to limit messages 5 years ago

README.md

Run a command each time you find mail in your mailbox.

The idea comes from "crontab based on imap events", but then became something different.

Howto

The main configuration file is called an "imaptab"

Imaptab

It is a TOML file. Might contain password, so you should chmod 0400 it.

Each account has a unique name and defines:

  • server address, username, password, etc
    • password can actually be avoided using password_file. This is the name of a file which contains the password. See the example below for its usage.
  • actions!

Each action has a unique name and defines:

  • command to run (you are invited to change uid/privileges with wrappers such as setuidgid, firejail, etc)
  • pre-validation (ie: validDomains)
  • deletion upon success bool

An example:

dbpath = /home/me/.imaptab.db
[accounts.nagios.imap]
hostname = "myimap.example.org"
port = 993
username = "notifications"
password = "iup"
folder = "INBOX"
since = "P1W"

[accounts.nagios.actions.notify]
command = ["setuidgid", "looser", "notify-send", "check nagios"]
pipe = false
validDomains = ["example.org"]
deleteAfter = false

[accounts.nagios.actions.sql]
command = ["/opt/dbscripts/nagios2mysql"]
pipe = true
validDomains = ["example.org"]
deleteAfter = false

[accounts.sudo.imap]
hostname = "myimap.example.org"
port = 993
username = "admin"
password_file = "/home/asd/passwords/admin@myimap"
folder = "INBOX"
since = "PT1H30M"

[accounts.sudo.actions.logger]
command = ["logger", "-t", "sudo-notifications"]
pipe = true
deleteAfter = true

[accounts.sudo.actions.notify]
command = ['sh', '-c', 'notify-send "check mail" "$IMATAB_SUBJECT"]
pipe = true
deleteAfter = true

(where nagios2mysql could be some script that parses the email and insert relevant fields into some mysql table).

Commands

A command is essentially 'reacting' to your email. Your emails are 'events'.

Your command will receive data on stdin.

However, since parsing emails is boring and often unneeded, some convenience environmente variables will also be set, so that most commonly accessed fields don't even need to be parsed:

  • IMAPTAB_SUBJECT
  • IMAPTAB_TO (semicolon-separated addresses)
  • IMAPTAB_FROM
  • IMAPTAB_CC
  • IMAPTAB_RECIPIENTS
  • IMAPTAB_MESSAGEID (especially useful to reply to emails!)

By default, you'll get the full message in stdin. It will need to be properly parsed. However, the flag pipe_body_text = true will allow your command to only receive a "textual" representation of the email. It's definitely nothing magic that you couldn't do by yourself, but this makes it even more convenient.

In some occasion you'd prefer not to receive stdin. This is especially the case if

  1. you want to run some command which is already present on your system
  2. you do not need the full message body
  3. that command will act differently when there is stdin attached, in a way that you don't want

Then, do pipe=false

Corner cases

What happens when I receive the same message on multiple accounts that I am checking with imaptab?

(This might be the case if a mail has multiple recipients, and your imaptab checks many of them). If account A has actions foo and bar while account B has actions xyz and grunt, then they all will be accessed. If, however, there is one action with the same name, it will be executed exactly once. You might wonder which will be executed, but there is no way to determine this.

The lesson is: action name is of free choice, but you should repeat only if the action is actually the same, and you want the action to only be executed once.

Status

Seems to work.

Expect glitches and breaking changes in the future.