MAILMUNGE-NOTIFY(7)

πŸ“¦ version 3.20, in alpine 3.24

πŸ’Œ MAILMUNGE-NOTIFY(7) β€” the mailmunge-notify page, but make it make sense πŸ’Œ

okay so real talk, this is from the User Contributed Perl Documentation corner of the manual-verse, and it's about mailmunge-notify β€” the whole vibe of how mailmunge-multiplexor slides into an external program's DMs to tell it when state changed. bestie, it's giving group chat notifications but for daemons πŸ’…


✨ NAME ✨

mailmunge-notify β€” the conventions that mailmunge-multiplexor uses to notify an external program when state changes happen πŸ¦‹

🌸 DESCRIPTION 🌸

okay so here's the tea: if you hand the -O option to mailmunge-multiplexor, it opens up and lets external programs connect to a socket and get pinged whenever certain state changes happen in the multiplexor πŸ‘‘

Those external programs can react however they want β€” no judgement, live your truth. And the external program that's sitting there listening for state changes? It's literally called a listener. iconic naming, no notes πŸŽ€

πŸ”” NOTIFICATION OVERVIEW πŸ””

from a listener's POV, the whole thing goes like this, bestie:

  1. The listener connects to a TCP or UNIX-domain socket.
  2. The listener tells mailmunge-multiplexor which message types it's interested in.
  3. The listener just loops forever, reading messages off the socket and reacting to them. main character energy fr fr ✨

πŸ’¬ MESSAGES πŸ’¬

Each message coming from the multiplexor is normally one single upper-case letter, maybe followed by a space and some arguments, then a newline. cute, compact, efficient 🧚

Two special messages exist, and they're the exceptions to the rule:

  • *OK followed by a newline β€” this one drops when a listener first connects 🫢
  • *ERR followed by some text and a newline β€” this one drops when an error happens 😭

Now the normal messages, one by one:

  • B β€” issued whenever a worker gets killed because of a busy timeout πŸ’€
  • F n β€” issued whenever the number of free workers changes. The parameter n is the number of free workers πŸ“
  • R β€” issued whenever someone has forced a filter reread πŸ”₯
  • S n nmsg β€” issued whenever worker n's status tag changes. The status tag is a string showing what that worker is currently doing; the -Z option to the multiplexor lets the Perl code update the status tag, so you get a good idea of what each worker is up to πŸ‘€
  • U β€” issued whenever a worker has died unexpectedly πŸ™ˆ
  • Y β€” issued whenever the number of free workers changes from zero to non-zero ⭐
  • Z β€” issued whenever the number of free workers falls to zero 😬

πŸ™‹ EXPRESSING INTEREST πŸ™‹

so a listener doesn't get anything until it has expressed interest in the message types it cares about. no interest, no messages, periodt.

To express interest, the listener sends a question mark (?) followed by the types of messages it's interested in, followed by a newline, over the socket πŸ’Œ

For example, a listener that's into the R and F messages would send this line:

?RF

And a listener that wants literally every possible message type should send:

?*

Once a listener has expressed interest, messages can arrive at any time, so it should be monitoring the socket for them πŸ‘‘

πŸ’œ heads up bestie: a listener always receives the special *OK and *ERR messages, even if it never expressed interest in them. they're the ride-or-dies that come with every subscription, no opt-out.

πŸ§ͺ EXAMPLE πŸ§ͺ

The following Perl script implements a listener that, on Linux, rejects new SMTP connections if all workers are busy, and accepts them again once a worker is free 🌈

Existing SMTP connections are not shut down β€” the system merely refuses new connections if all the workers are busy. no cap, that's the whole scope.

This script assumes you've used the -O inet:4567 option to mailmunge-multiplexor πŸŽ€

#!/usr/bin/perl -w
#
# On Linux, prepare to use this script like this:
#     /sbin/iptables -N smtp_connect
#     /sbin/iptables -A INPUT --proto tcp --dport 25 --syn -j smtp_connect
# Then run the script as root.

use IO::Socket::INET;

sub no_free_workers {
    print STDERR "No free workers!\\n";
    system("/sbin/iptables -A smtp_connect -j REJECT");
}

sub some_free_workers {
    print STDERR "Some free workers.\\n";
    system("/sbin/iptables -F smtp_connect");
}

sub main {
    my $sock;

    $sock = IO::Socket::INET->new(PeerAddr => '127.0.0.1',
                                  PeerPort => '4567',
                                  Proto => 'tcp');
    # We are only interested in Y and Z messages
    print $sock "?YZ\\n";
    $sock->flush();
    while(<$sock>) {
        if (/^Z/) {
            no_free_workers();
        }
        if (/^Y/) {
            some_free_workers();
        }
    }

    # EOF from multiplexor?? Better undo firewalling
    system("/sbin/iptables -F smtp_connect");
}

main();

lowkey obsessed with that last comment ngl β€” "EOF from multiplexor?? Better undo firewalling" is such a mood 😭

πŸ‘€ SEE ALSO πŸ‘€

mailmunge-multiplexor, mailmunge, mm-mx-ctrl β€” go read those too, iykyk πŸ’–

✍️ AUTHOR ✍️

mailmunge was written by Dianne Skoll <dianne@skollsoft.com> πŸ‘‘

πŸ“œ LICENSE πŸ“œ

This code is licensed under the terms of the GNU General Public License, version 2 πŸ¦‹


and that's the whole page, bestie! πŸ’œ this one's perl v5.42.2, dated 2025-10-05 β€” slay, go forth and listen for state changes πŸŽ€βœ¨

πŸ“¦ where this page comes from