${COURIER_HOME}/lib/modules contains shared
  libraries and programs which provide input and output modules to
  Courier. The actual module itself can actually be installed and
  invoked anywhere else, the SMTP module, in fact, is installed in
  bin. The shared library in lib, however, may include functions
  which rewrite addresses for messages submitted from the input
  module. All files for module named MODULE are stored in the
  directory ${COURIER_HOME}/lib/modules/MODULE.
  modules.ctl file${COURIER_HOME}/lib/modules/modules.ctl contains a
  list of all the modules that Courier loads.
  modules.ctl is only used if Courier is compiled with
  shared library support. If Courier is compiled with static
  linkage only (by choice, or by necessity), all the module
  libraries are statically linked into Courier, and
  modules.ctl is not used. Each line in modules.ctl is
  in the following form:
  priority<SP>name<SP>filename,
  where <SP> designates the space character. The
  lines are sorted in increasing priority order! "priority" is
  taken from the module's config file, and filename is the
  filename of the shared library.
  ${COURIER_HOME}/lib/modules/name
  directorymodules.ctl file.
  NAME=VALUE
  notation, where NAME is the name of the
  configuration parameter, and VALUE is its value.
  submit and courierd. The shared library
  provides code to rewrite addresses to and from the canonical
  format for messages to or from this module. If Courier is
  compiled with static linkage, this file does not exist - the
  library is statically linked.
  The actual name of the library may vary, and is specified in
  the config file.
If this shared library does not exist, an attempt is made to
  load librewrite-old. This allows an updated version
  of the shared library to be installed in a live, running, system
  by renaming the current one to librewrite-old, then
  renaming the new one to librewrite.
Although submit will pick up new rewriting rules immediately,
  courierd must be SIGHUPed in order to reload the new
  shared library.
NAME=name - specifies
  the name of this module. Should be the same as the directory
  name.
  LIBRARY=filename - specifies the name of the
  shared library to load. Not used if Courier was compiled with
  static libraries.
VERSION=version - version of the module
  interface. Not the actual version of the module, but version of
  the interface between the module, and Courier. The current
  version is version 0.
PRIORITY=n - priority of the output module.
  Courier calls all the modules' rewritedel functions
  in the increasing priority order until it finds one which accepts
  messages addressed to the recipient's address.
PROG=pathname - pathname to the output module
  program. Must be a full path, unless the module itself is in the
  lib/MODULE directory.  If the PROG
  parameter is missing, this module is an input only module. If the
  attempt to execute PROG fails, Courier will attempt
  to execute PROG-old, which allows an updated output
  module to be inserted into a live system by renaming the current
  one PROG-old, then renaming the new output module as
  PROG.
MAXDELS=n - maximum concurrent deliveries for
  this module. No more than these many instances of
  PROG will be started at any given time.
MAXHOST=n - maximum instances of
  PROG that will be started with the same
  HOST parameter.
MAXRCPT=n - maximum number of addresses that will
  be given to any single instance of PROG.
Please note that although these parameters are reread by
  courierd when it restarts, the individual output
  module may impose its own restrictions on the valid limits for
  these parameters.
XXXX is used to
  represent the name of the function in the library for module
  XXXX. For example, in the "local" module, the
  rw_install function is called
  local_rw_install.
  struct rw_list *XXXX_rw_install(const struct
  rw_install_info *info);
The rw_install() function is called after the
  shared library is open. It receives a pointer to the following
  structure:
struct rw_install_info {
        int rw_verlo;
        int rw_verhi;
        const char *courier_home;
        } ;
rw_verlo/rw_verhi - reserved for future
expansion. Currently set to 0. rw_install function of
modules compatible with this Courier interface must check that
rw_verlo is set to 0, and ignore
rw_verhi.
  courier_home - Courier's home directory, the
  shared library can use this to find its files.
rw_search functionstruct rw_list *rw_search(const char *);The
rw_search function can be called by a
library function in order to return the rw_list (see below)
structure of a function in another library. rw_search
may NOT be called form XXXX_rw_install, because the
library containing this function may not've been installed yet.
rw_search may be called from the
XXXX_rw_init function.
  const char *XXXX_rw_init()
After all modules are installed, each module's
  rw_init() function is called, which can complete any
  additional setup. rw_init should return a null
  pointer. Otherwise, rw_init should return the error
  message text. Courier will refuse to start if
  rw_init does not return a null pointer.
The library's rw_install function must return a
  pointer to the following structure. If rw_install
  returns a NULL pointer, Courier will refuse to start.
struct rw_list {
        int rw_version;
        void (*rewrite)(struct rw_info *info, void (*func)(struct rw_info *));
        void (*rewrite_del)(struct rw_info *info, void (*func)(struct rw_info *),
                    void (*delfunc)(struct rw_info *info, const struct rfc822token *host,
                                const struct rfc822 *addr));
        int  (*filter_msg)(const char *,
                        int,
                        const char *,
                        const char *,
                        const char *,
                        char *,
                        unsigned);
} ;
rw_version - shared libraries compatible with
this module interface must set rw_version to zero.
  rewrite - this function is called to rewrite a
  single address. The first argument points to the following
  structure:
   
struct rw_info {
    int mode;
    struct rfc822token *ptr;
    void (*err_func)(int, const char *, struct rw_info *);
    const struct rfc822token *sender;
    const char *smodule;
    void *udata;
} ;
mode contains the following values, ORed into a
bitmask: RW_ENVSENDER - rewrite envelope sender,
RW_ENVRECIPIENT - rewrite envelope recipient,
RW_HEADER - rewrite header. When calling
rewrite(), one of these three bits will be set.
Additional bits that may be set: RW_OUTPUT -
rewrite() should convert canonical format to the
transport format. If this bit is not set, rewrite should convert
from the transport format to the canonical format. In fact, the
main courierd does not call rewrite with the
RW_OUTPUT bit set, because that function is performed
by the dedicated output module, which may handle rewriting on its
own. Also, the RW_SUBMIT can be set together with
RW_ENVSENDER or RW_ENVRECIPIENT,
indicating that this call is as a result of a message being
submitted for delivery (as opposed to address verification for
EXPN/VRFY functionality).
  It is possible that none of those bits are set, when invoked by another rewrite function.
ptr is the address to rewrite, as rfc822
  tokens.
udata contains an arbitrary pointer, for usage by
  rewrite's caller.
When mode has RW_ENVRECIPIENT set,
  sender points to the envelope sender format in the
  canonical format (previous result of RW_ENVSENDER),
  otherwise this field is unused. If sender is NULL,
  this should be interpreted as an empty envelope sender (or if
  rewrite is being called in test mode.
smodule is initialized when mode has the
  RW_SUBMIT bit set. It will point to the name of the
  module argument to submit - the module sending the message.
err_func is the function to call in case of an
  error.
rewrite is expected to call either
  func, (it's second argument), or
  err_func, before returning. If rewriting succeeds,
  func is called. If rewriting failed,
  rewrite must call the err_func is
  function. errcode will be the RFC822-style error
  number, errmsg is the error message, which may be
  multiline (includes newlines). The text in errmsg is
  NOT prefixed by the error number.
After calling func, or err_func,
  rewrite is expected to immediately terminate.
  rewrite may alter the 'ptr' link list in any form or
  fashion it wants, except that it may NOT malloc or free any node,
  or a part thereof. However, it can relink portions of the link
  list, or modify the link pointers to include tokens created by
  rewrite internally.
After func or err_func terminates,
  rewrite may deallocate everything it allocated, then
  terminate itself.
This interface allows rewrite to execute very quickly, without allocating or deallocating any memory. If new RFC822 tokens are required, they can be allocated on the stack, and linked into the original list.
The rewrite_del function is called to determine
  if the module can accept delivery of a message to this address.
  The rewrite_del of all installed libraries are
  called until one of them calls the delfunc function.
  If rewrite_del cannot accept delivery of a message,
  it should call func. The rewrite_del
  function should call the delfunc function to
  indicate that this module can accept mail addressed to the
  address specified by info->ptr.
  rewrite_del receives the pointer to the rw_info
  structure, then the host and the
  address information for the output module, as
  rfc822token lists. If the mode field has the
  RW_SUBMIT bit set, rewrite_del can find the
  message's envelope sender address in canonical format) in
  info->sender.
Like rewrite, rewrite_del may make
  arbitrary changes to info->ptr, except that it
  may not deallocate memory used for the existing list.
  rewrite_del may modify the link list, and allocate
  memory for new rfc822 tokens. After calling either
  func or delfunc,
  rewrite_del should terminate immediately, and
  deallocate any allocated memory. rewrite_del must
  keep track of any allocated memory separate, and cannot assume
  that info->ptr hasn't changed.
When RW_SUBMIT bit is set,
  rewrite_del can be used to perform additional
  recipient-specific code, which may be too expensive to run every
  time courier goes through the queue. The udata field
  contains a pointer to caller-specific data. The
  sender field contains a pointer to the envelope
  sender, in canonical format. Like rewrite,
  rewrite_del may muck around with the
  rfc822token list in ptr.
  rewrite_del functions are called in order according
  to the configured module priority. By setting a higher priority,
  it is possible to have rewrite_del rewrite the
  address so that it would be accepted by another module's
  rewrite_del, down the chain.
The last function, rw_filter_msg, is called to
  run an arbitrary spam filter which can be used to selectively
  reject messages. rw_filter_msg will be called after
  rewrite_del accepted the message for delivery. The
  arguments are as follows:
rewrite_del, as a
    text string.rewrite_del, as a
    text string.rw_filter_msg should return 0 if the message is
  acceptable, a negative value to permanently reject the message to
  this recipient, and a positive value for a temporary
  rejection.
   
PROGPROG is the output
  module that will be started by Courier when it comes up. PROG can
  be a shell command, it is executed via "$SHELL -c".
  It will be started under userid mail, group mail, in
  ${COURIER_HOME}/lib/modules/NAME. Courier will
  communicate with PROG on standard input and output.
  If PROG succesfully initializes, it should fork,
  and the parent should exit with status of 0. Courier waits until
  PROG exits. If it exits with a non-0 exit code,
  Courier will fail starting up. The child process will then
  continue to read and write from standard output.
COURIER_HOME, MAXDELS,
  MAXHOST, and MAXRCPTS will be placed in
  the environment, prior to executing PROG.
Tip: if the environment variables are not set,
  PROG can presume that it's being run in test mode,
  from the command line, and forego the fork.
If PROG terminates, Courier will consider it a
  fatal error (Courier detects the input channel being closed).
If PROG gets an end-of-file indication, it can
  assume that Courier is being shut down, so it should promptly
  cease all activities, without waiting for pending messages to be
  delivered.
To start delivery for a particular message, PROG
  will receive a newline-terminated command, specifying the
  message, and the recipients, and the delivery ID. Once
  PROG finishes delivering messages, PROG
  should write the results of the delivery into the message's
  control file, then print the delivery ID on its standard output,
  terminated by newline.  If the module's config file
  specifies that the module can handle multiple deliveries at the
  same time, PROG may receive additional deliveries
  before it finishes delivering the first message.
The command that prog receives is a newline-terminated line that looks like this:
msgnum<tab>sender<tab>delid<tab>host<tab>num1<tab>addr1<tab>num2<tab>addr2...
<tab> represents the ASCII tab character. This is basically a list of tab-separated fields. The first field is the message id number (the inode number).
sender is the message envelope sender, after it's rewritten to the module format, by the module shared library.
delid is the "delivery ID", which is a small integer,
  representing this delivery. After PROG finishes
  delivering the message, it should print the message's delivery ID
  on standard output after saving the delivery status of each
  recipient in the control file.
The host field specifies the host where the message should be
  delivered to, as determined by the module's output rewrite rule.
  Following the host, there will be one or more num/address pairs.
  address is the recipient's address as determined by the output
  rewrite rule, and num is the recipient's number in the message's
  list of recipients (this is used to save the delivery status in
  the control file). Note that the address can be an empty string,
  so there will be two consecutive tabs there.