Sendmail Operation Guide

Configuration in src/conf.c

This topic discusses the changes that can be made in conf.c.

Built-in header semantics

Not all header semantics are defined in the configuration file. Header lines that should only be included by certain mailers (as well as other more obscure semantics) must be specified in the HdrInfo table in conf.c. This table contains the header name (which should be in all lower case) and a set of header control flags. The flags are:

Here is a sample HdrInfo specification:
   struct hdrinfo	HdrInfo[] =
   {
   	     /* originator fields, most to least significant  */
   	"resent-sender",	H_FROM,
   	"resent-from",	H_FROM,
   	"sender",	H_FROM,
   	"from",	H_FROM,
   	"full-name",	H_ACHECK,
   	"errors-to",	H_FROM|H_ERRORSTO,
   	     /* destination fields */
   	"to",	H_RCPT,
   	"resent-to",	H_RCPT,
   	"cc",	H_RCPT,
   	"bcc",	H_RCPT|H_STRIPVAL,
   	     /* message identification and control */
   	"message",	H_EOH,
   	"text",	H_EOH,
   	     /* trace fields */
   	"received",	H_TRACE|H_FORCE,
   	     /* miscellaneous fields */
   	"content-transfer-encoding",	H_CTE,
   	"content-type",	H_CTYPE,
   

NULL, 0, };

This structure indicates that the To:, Resent-To:, and Cc: fields all specify recipient addresses. Any Full-Name: field will be deleted unless the required mailer flag (indicated in the configuration file) is specified. The Message: and Text: fields will terminate the header; these are used by random dissenters around the network world. The Received: field will always be added, and can be used to trace messages.

There are a number of important points here. First, header fields are not added automatically just because they are in the HdrInfo structure; they must be specified in the configuration file in order to be added to the message. Any header fields mentioned in the configuration file but not mentioned in the HdrInfo structure have default processing performed; that is, they are added unless they were in the message already. Second, the HdrInfo structure only specifies cliched processing; certain headers are processed specially by ad hoc code regardless of the status specified in HdrInfo. For example, the Sender: and From: fields are always scanned on ARPANET mail to determine the sender; this is used to perform the ``return to sender'' function. The From: and Full-Name: fields are used to determine the full name of the sender if possible; this is stored in the macro $x.

Restricting use of email

If it is necessary to restrict mail through a relay, the checkcompat routine can be modified. This routine is called for every recipient address. It returns an exit status indicating the status of the message. The status EX_OK accepts the address, EX_TEMPFAIL queues the message for a later try, and other values (commonly EX_UNAVAILABLE) reject the message. It is up to checkcompat to print an error message (using usrerr) if the message is rejected. For example, checkcompat could read:

   int
   checkcompat(to, e)
       register ADDRESS *to;
       register ENVELOPE *e;
   {
       register STAB *s;
   

s = stab("private", ST_MAILER, ST_FIND); if (s != NULL && e->e_from.q_mailer != LocalMailer && to->q_mailer == s->s_mailer) { usrerr("No private net mail allowed through this machine"); return (EX_UNAVAILABLE); } if (MsgSize > 50000 && bitnset(M_LOCALMAILER, to->q_mailer)) { usrerr("Message too large for non-local delivery"); e->e_flags |= EF_NORETURN; return (EX_UNAVAILABLE); } return (EX_OK); }

This would reject messages greater than 50000 bytes unless they were local. The EF_NORETURN flag can be set in e->e_flags to suppress the return of the actual body of the message in the error return. The actual use of this routine is highly dependent on the implementation, and use should be limited.

Load average computation

The routine getla should return an approximation of the current system load average as an integer. There are several versions of the load average computation system. See the description of the LA_TYPE option in ``Parameters in src/conf.h''.

New database map classes

New key maps can be added by creating a class initialization function and a lookup function. These are then added to the routine setupmaps.

The initialization function is called as

   xxx_map_init(MAP *map, char *mapname, char *args)
The map is an internal data structure. The mapname is the name of the map (used for error messages). The args is a pointer to the rest of the configuration file line; flags and filenames can be extracted from this line. The initialization function must return TRUE if it successfully opened the map, FALSE otherwise.

The lookup function is called as

   xxx_map_lookup(MAP *map, char buf[], int bufsize, char **av, int *statp)
The map defines the map internally. The parameters buf and bufsize have the input key. This may be (and often is) used destructively. The av is a list of arguments passed in from the rewrite line. The lookup function should return a pointer to the new value. If the map lookup fails, *statp should be set to an exit status code; in particular, it should be set to EX_TEMPFAIL if recovery is to be attempted by the higher level code.

Queueing function

The routine shouldqueue is called to decide if a message should be queued or processed immediately. Typically this compares the message priority to the current load average. The default definition is:

   bool
   shouldqueue(pri, ctime)
       long pri;
       time_t ctime;
   {
       if (CurrentLA < QueueLA)
           return (FALSE);
       return (pri > (QueueFactor / (CurrentLA - QueueLA + 1)));
   }
If the current load average (global variable CurrentLA, which is set before this function is called) is less than the low threshold load average (option x, variable QueueLA), shouldqueue returns FALSE immediately (that is, it should not queue). If the current load average exceeds the high threshold load average (option X, variable RefuseLA), shouldqueue returns TRUE immediately. Otherwise, it computes the function based on the message priority, the queue factor (option q, global variable QueueFactor), and the current and threshold load averages.

An implementation wishing to take the actual age of the message into account can also use the ctime parameter, which is the time that the message was first submitted to sendmail(1M). Note that the pri parameter is already weighted by the number of times the message has been tried (although this tends to lower the priority of the message with time); the expectation is that the ctime would be used as an escape clause to ensure that messages are eventually processed.

Refusing incoming SMTP connections

The function refuseconnections returns TRUE if incoming SMTP connections should be refused. The current implementation is based exclusively on the current load average and the refuse load average option (option X, global variable RefuseLA):

   bool
   refuseconnections()
   {
       return (RefuseLA > 0 && CurrentLA >= RefuseLA);
   }

© 2000 The Santa Cruz Operation, Inc. All rights reserved.