27

On my laptop, I have set up a cron that performs a weekly job. If there is something to report, I would like to get an e-mail for it. Right now I am using KMail as MUA which is able to read mail from the Maildir directory at ~/.local/share/local-mail. Thus, I want local mail to be delivered to that folder (with a Maildir structure).

I was hoping that a dead simple program already exist that has a sendmail interface (such that echo "$REPORT" | mail -s "$SUBJECT" "$ME" can work with it). Installing exim or forwarding mail to my remote mailserver is considered overkill.

The question Simplest way of forwarding all mail from server? seems to target remote forwarding which does not suit my needs (I need local delivery). This old Gentoo thread ended up in crafting an old script in Perl. Surely there must exist a well-thought, dead-simple program?

Any recommendations? I am using Arch Linux.

5
  • Presuming whatever MTA Arch uses by default is installed and running, you could just use [email protected] and the stuff should end up in /var/spool/mail/userX; you can check this yourself or create a new account to check with your MUA.
    – goldilocks
    Jul 7, 2013 at 16:44
  • 3
    Some googling brought me to github.com/corecode/dma aka Dragonfly Mail Agent.
    – tripleee
    Jul 7, 2013 at 17:05
  • @goldilocks Arch being a minimal distribution does not have a MTA installed by default. /usr/bin/sendmail does not exist and cron output end up in /dev/null.
    – Lekensteyn
    Jul 7, 2013 at 20:17
  • @tripleee I encountered that but ignored it once I saw SMTP and TLS being mentioned. Thanks for mentioning, I will have a look again. does not listen on port 25 sounds good to me.
    – Lekensteyn
    Jul 7, 2013 at 20:18
  • @tripleee Unfortunately, dma does not support Maildir, only spool dirs in /var/spool/mail.
    – Lekensteyn
    Jul 8, 2013 at 13:40

2 Answers 2

9

Since I could not find an existing, small program, I decided to write my own one. Originally, I came up with:

#!/bin/bash
# Simple sendmail
# filename per spec at http://cr.yp.to/proto/maildir.html
rand=$((RANDOM % 1000))
msgname=$(date +%s).P$$R$rand.$(hostname | tr '/:' '\057\072')

# Safety measure: do not overwrite existing mail
set -o noclobber

cat > ~peter/".local/share/local-mail/inbox/new/$msgname"

That worked... except if the user executing the script is not "peter". The successor of this idea is a "small" C program, femtomail. From its README:

femtomail - minimal MDA with Maildir support

femtomail is a minimal Mail Delivery Agent (MDA) for local mail. Mail is accepted from standard input and placed in a Maildir box of a user. This software is intended for use on a single-user machine.

Remote delivery, daemonizing, sender verification, etc. is not implemented and won't be implemented due to its complexity. femtomail is not written because mail software did not exist, but because existing software were too large for the simple task of delivering cron mail to the local user.

The workflow of femtomail:

  1. Change the process user and group.
  2. Create a new file with a unique filename in the mail directory.
  3. Write a Received header to the file.
  4. Pass data from standard input to the file.
  5. Exit.

The source code and installation instructions are available at https://git.lekensteyn.nl/femtomail/.

6
  • 1
    it would be great if femtomail could: read user@localhost (or hostname of local host) and setuid that user, write the email either in home dir or somewhere standard. would require setuid bits.
    – gauteh
    Nov 20, 2014 at 17:25
  • @gauteh That is already more advanced and probably not for use on a single-user machine. More features means larger code and a greater chance of bugs. What is your use case?
    – Lekensteyn
    Nov 20, 2014 at 22:03
  • definetely, to use it as a complete local mail delivery agent, between users - without hardcoded stuff.
    – gauteh
    Nov 22, 2014 at 10:19
  • 1
    @gauteh I think you are better off with a more complete MDA such as Dovecot for that use case. You are free to patch femtomail for your use case though, and maybe even send a PR in case others are interested.
    – Lekensteyn
    Nov 22, 2014 at 11:07
  • I miss the reason for step 1, because cron already runs your job as your UID and GID.
    – q.undertow
    Nov 16, 2021 at 17:13
0

Based on the accepted answer, I've created a small solution using the Docker image form the official Dovecot CE repository at https://hub.docker.com/r/dovecot/dovecot, which I'd like to share.

  1. Run the container:

    docker run --name dovecot -d dovecot/dovecot
    
  2. Install sudo, which isn't included in the dovecot image, but needed for our script

    apt-get update && apt-get -y install sudo
    
  3. Set up a mail directory. I found it to be more flexible and less hassle to do so in /var/mail rather than in the user home directory:

     mkdir /var/mail/vmail
     chown vmail /var/mail/vmail  
    
  4. Create a mailbox user, who must be member of the vmail group:

     useradd -g vmail theresa
    

    You can add more users anytime if need be.

  5. Tell Dovecot where the mail is. To do so, we need to change mail_location in /etc/dovecot/dovecot.conf to this:

     mail_location=maildir:/var/mail/vmail/%u
    

    You need to restart dovecot afterwards, which can be done by simply restarting the Docker container:

     docker restart dovecot
    
  6. Create the following bash script at /usr/local/storemail.sh in the dovecot container:

     #!/bin/bash
    
     # Store mail in maildir
     # Based on https://unix.stackexchange.com/a/82367/215688
    
     # Simply stores an email to the user mail directory 
    
     USER=$1
    
     MAIL_LOCATION="/var/mail/vmail/$USER"
     # filename per spec at http://cr.yp.to/proto/maildir.html
     rand=$((RANDOM % 1000))
     msgname=$(date +%s).P$$R$rand.$(hostname | tr '/:' '\057\072')
    
     # Just in case the user dir has not been created yet
     sudo -u vmail mkdir -p "$MAIL_LOCATION/new"
    
     # Safety measure: do not overwrite existing mail
     set -o noclobber
    
     # now store the email there
     sudo -u vmail cat > "$MAIL_LOCATION/new/$msgname"
    

    Don't forget to make it executable:

     chmod +x /usr/local/storemail.sh
    

That's it.

Now you can store a new mail using the script. The only argument is the username, and the email needs to be provided from stdin.

    storemail.sh theresa <testmail.eml

Or from outside the container use

    docker exec -i dovecot <testmail.eml storemail.sh theresa

Or even from a remote machine via ssh

    ssh docker-machine.local <testmail.eml docker exec -i dovecot storemail.sh theresa
    

I recommend to create a custom dockerfile that automates the preparation steps.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .