Linux – How to rate-limit outgoing email on Linux/Postfix host

emaillinuxpostfixrate-limiting

Background: I'm a fan of David Allen's Getting Things Done, and that means when an email arrives in my inbox, if I can reply right away, I want to do so and keep my inbox clear. But there's a problem: if I reply immediately, the chances of my getting a reply to the reply go up. So I want to rate-limit my email by putting a delay on some outgoing messages. Delays of an hour, four hours, or even a day would be suitable for my needs.

My question is how best to implement this idea on a Linux system running postfix?

Here are a few observations:

  • I can easily put an X-Delay: header in any outgoing message to say that the message should be delayed, and by how much.
  • I can easily interpose something between my Mail User Agent and sendmail.
  • Email is as close as I get to a mission-critical service. Outgoing mail must be utterly reliable.
  • I want to avoid duplicating the reliable queue service that is already in Postfix.
  • It appears that Postfix almost has what I want already. There is a facility called header_checks(5) which will inspect headers and take actions, but although there is an action to place mail into the "hold" queue, there is no action to place mail into the "deferred" queue. If I could reliably get an email into the "deferred" queue with a suitable timestamp (i.e., N hours in the future), I think my problem would be solved.

All suggestions are welcome, although I would prefer not to be in the business of patching Postfix…

Best Answer

I gave up on using postfix to solve this problem. Instead, I found a relatively clean way to solve the problem using MH, which is the mailer I have been using for over 15 years:

  1. An outgoing mail that should be delayed by N hours is composed in the MH "draft folder" +delayN.

  2. When I have finished composing the mail, to ensure that I leave the mail in the folder instead of sending it, I have a modified whatnow program that treats send as a synonym for quit if the message is stored in a folder whose name has the form delayNNN, where NNN is a nonempty sequence of digits.

  3. My hourly cron job checks all relevant folders and ships files that are old enough (details elided):

    for path in $MAIL/delay*[0-9]
    do
      minutes=...
      for outgoing in $(find $path -mmin +$minutes -name '[0-9]*')
      do
        folder=... 
        msg=...
        send -draftfolder +$folder -draftmessage $msg
      done
    done