When sendmail prepares to deliver mail, it first checks the size of the mail message and rejects (bounces) it if it is larger than the limit imposed by the M= delivery agent equate (see M=). V8.8 and above sendmail then call the check_compat rule set (see Section 7.1.4). After that, all versions of sendmail call the checkcompat( ) routine.
The checkcompat( ) routine lies in a unique position within the sendmail code. It is the one place where both the sender and already aliased recipient addresses are available at the same time. Because it is invoked immediately before actual delivery, all the information needed for delivery is available to you for checking.
If checkcompat( ) returns EX_OK, as defined in <sysexits.h>, the mail message is considered OK and delivered. Otherwise the message is bounced. If you wish the message to be requeued instead of bounced, you can return EX_TEMPFAIL.
Again note that the checkcompat( ) routine is called once for each already aliased recipient.
The checkcompat( ) is found in the C-language source file sendmail/conf.c. Inside that file you will find it declared like this:
checkcompat(to, e) register ADDRESS *to; register ENVELOPE *e;
Here, to is a pointer to a structure of typedef ADDRESS which contains information about the recipient. And e is a pointer to a structure of typedef ENVELOPE which contains information about the current envelope. (Actually, both are linked lists of structures.)
The members of the ADDRESS *to structure are shown in Table D-1. Note that these members are correct for V8.12 sendmail only. Also note that the table shows only those members that can be useful in a checkcompat( ) routine (see sendmail.h for the other members of *to).
Type |
Member |
Description |
---|---|---|
struct address * |
q_alias |
The alias that yielded this address |
char * |
q_finalrcpt |
This is a Final-Recipient: DSN header |
unsigned long |
q_flags |
Address flags (see Table 16-3) |
char * |
q_fullname |
The (GECOS) full name of q_ruser, if known |
gid_t |
q_gid |
The gid of the q_ruser, if known |
char * |
q_home |
The home directory (path), if F=w delivery-agent flag is set |
char * |
q_host |
The host part ($@) from rule set 0 (seeSection 19.5) |
struct mailer * |
q_mailer |
The delivery agent ($#) from rule set 0 (see Section 19.5) |
char * |
q_message |
Message regarding address (not always an error) |
struct address * |
q_next |
Link to the next ADDRESS in the chain |
char * |
q_orcpt |
The ORCPT parameter from RCPT TO: line was set |
char * |
q_owner |
The owner of q_alias |
char * |
q_paddr |
The address in a form suitable for printing |
int |
q_qdir |
Queue directory inside group |
int |
q_qgrp |
Index into queue groups |
char * |
q_ruser |
The login name for this user, if known |
time_t |
q_statdate |
The date of the status change |
short |
q_state |
The state of the address |
char * |
q_statmta |
Which MTA generated q_rstatus |
uid_t |
q_uid |
The uid of the q_ruser, if known |
char * |
q_user |
The user part ($:) from rule set 0 (seeSection 19.5) |
The members of the ENVELOPE *e structure are shown in Table D-2. Note that these members are correct for V8.12 sendmail only. Also note that the table shows only those members that can be useful in a checkcompat( ) routine (see sendmail.h for other members of *e).
Type |
Member |
Description |
---|---|---|
char * |
e_auth_param |
The parameters set by AUTH= |
char * |
e_bodytype |
The type of message body |
short |
e_class |
The message class (priority, junk, etc.) |
time_t |
e_ctime |
The time this message was accepted |
long |
e_deliver_by |
The DELIVERYBY BY= interval |
int |
e_dlvr_flag |
The DELIVERYBY BY= flags |
SM_FILE_T * |
e_dfp |
The datafile |
int |
e_dfqgrp |
The datafile's queue group index |
int |
e_dfqdir |
The datafile's queue directory index |
time_t |
e_dtime |
The time of the last delivery attempt |
char * |
e_envid |
Envelope ID from MAIL FROM: |
short |
e_errormode |
The error return mode |
ADDRESS * |
e_errorqueue |
The queue for error responses |
unsigned long |
e_flags |
Envelope flags (see Table 16-6) |
ADDRESS |
e_from |
The sender address structure |
char ** |
e_fromdomain |
The domain part of the sender |
HDR * |
e_header |
Linked list of headers |
short |
e_hopcount |
The hop count for the message |
char * |
e_id |
The ID for this entry |
char * |
e_message |
The error message |
char * |
e_msgid |
The message ID (for logging) |
long |
e_msgpriority |
The adjusted priority of this message |
long |
e_msgsize |
The size of the message in bytes |
int |
e_nrcpts |
The number of recipients |
int |
e_ntries |
The number of delivery attempts |
int |
e_qgrp |
The queue group (index into queues) |
int |
e_qdir |
The index into queue directories |
char * |
e_sender |
Sender address with comments stripped |
ADDRESS * |
e_sendqueue |
Linked list of recipients |
char * |
e_statmsg |
The status message (changes per delivery) |
char * |
e_status |
The DSN status for this message |
short |
e_timeoutclass |
The message timeout class |
The checkcompat( ) routine is a powerful internal hook inside sendmail. It is so internal and powerful, in fact, that if you are truly clever you can even use checkcompat( ) to modify rewrite rules at runtime (scary, but possible).
V8.8 sendmail uses more than 100 variables. They are all listed in sendmail.h and conf.c with "lite" comments. Global variables store information such as sendmail's option values, file descriptor values, macro values, class lists, and database access information. Any can be modified inside checkcompat, but before attempting to do so, study the sendmail C source code to anticipate any unexpected side effects.
In general you can use almost any of the global variables when designing your own checkcompat( ) routine. The four most interesting are:
The IP address of the sending host. This is a union of several sockaddr_ types depending on your selection of protocol types. This can be zero for locally submitted mail.
A string containing the definitive canonical name of the sending host. If it can't be resolved to a name, it will contain the host's IP number in text form, surrounded by square brackets.
This variable determines the amount of logging that sendmail does, and is set using the LogLevel option (LogLevel). You can use this LogLevel variable to decide how much, if anything, you wish to log about what you are doing inside the checkcompat( ) function.
An integer representation of the current load average. You might want to use checkcompat( ) to defer mail between selected senders and recipients when the load is very high.
An integer that, if it is nonzero, means that you can allow checkcompat( ) to show (print to the standard output) what it is doing.