The name part of the H configuration command can be prefixed with a list of flags. This list, if present, must be surrounded by ? characters:
H?flags?name:field
The ? characters must immediately follow the H and immediately precede the name with no intervening spaces. If a space precedes the first ?, that ? is misinterpreted as part of the header name, rather than as the start of a list of flags, and this error message is printed:
header syntax error, line " ?flags?name: field" note leading space
If the first ? is present but the second is absent, sendmail prints the same error message and skips that H configuration command. The flags that are listed between the ? characters correspond to flags that are listed with delivery agent F= equates. When processing a mail message for forwarding or delivery, sendmail adds a header line if a flag is common to both the H definition list of flags and the delivery agent's list of flags. For example:
H?P?Return-Path: <$g>
This H definition begins with a P flag. This tells sendmail to add this header line to the mail message only if a selected delivery agent also contains that flag. Because the Return-Path: header (Return-Path:) should be added only during final delivery, the P flag appears only in the prog and local delivery agent definitions:
Mprog, P=/bin/sh, F=lsDFMeuP , S=10, R=20, A=sh -c $u Mlocal, P=/bin/mail, F=rlsDFMmnP , S=10, R=20, A=mail -d $u note
No check is made to ensure that the H flags correspond to existing delivery agent flags. Beware that if a corresponding F= flag does not exist in some delivery agent definition, that header can never be added to any mail message.
Care should be used to avoid selecting flags that have other meanings for delivery agents. Table 20-19 in Section 20.8 lists all the delivery agent flags that have predefined meanings, including those traditionally used with header definitions.
Beginning with V8.12 it is possible to add a header to a message by placing a sendmail macro between the ? characters instead of, or in addition to, using flags (Section 25.4). But note that for V8.10 and V8.11 only, the ? character method was omitted, and only a macro could appear in that position:
H?flags?X-Added-Header: value all versions H${macro name}X-Added-Header: value V8.10 and V8.11 only H?${macro name}?X-Added-Header: value V8.12 and above H?${macro name}flags?X-Added-Header: value V8.12 and above
In the last three examples, if the macro has a value (is defined and is nonnull), the header will be added to the email message. If the macro lacks a value (was not defined or was defined to be an empty string), the header is not added to the message. The first and last examples cause the header to be added if a corresponding flag appears in the F= equate of the selected delivery agent.
Note that if the header is already in the message, it will remain there, regardless of whether the macro is defined, or whether a flag is in the appropriate F= equate.
To illustrate, consider dealing with a message that contains an illegally formed Message-Id: header:
LOCAL_CONFIG Kstorage macro HMessage-Id: $>ScreenMessageId H?${MsgId}?X-Authentication-Warning: ${MsgId} C{persistentMacros} {dsn_envid} LOCAL_RULESETS SScreenMessageId R < $+ @ $+ > $@ OK R $* $: $(storage {MsgId} $@ Illegal Message-Id: $1 $)
The LOCAL_CONFIG part of this mc file declares a macro-type database map (macro) that is used to store a value into a sendmail macro via a rule set.
The LOCAL_CONFIG part of this mc file continues with two H configuration file commands. The first says that each Message-Id: header in the message must be screened by the ScreenMessageId rule set. The use of the $> operator (Section 25.5) ensures that sendmail will strip RFC2822 parenthetical comments from the header's value. The second H line uses the V8.12 (and above) form of a macro between the ? characters. This tells sendmail to add this header if the ${MsgId} has or is given a value. We discuss the {persistentMacros} declaration soon.
The LOCAL_RULESETS part of this mc file declares a single rule set. The ScreenMessageId rule set has two rules. The first rule checks the workspace which contains the value of the Message-Id: header with RFC2822 parenthetical comments stripped. If that value is formed by a user and host part separated by an @ character and surrounded by angle brace characters, the Message-Id: header is correctly formed. By returning anything other than the $#error delivery agent, the message is allowed.
The second rule in the ScreenMessageId rule set matches everything (the $* in the LHS), so the RHS is always called. The RHS calls the storage database map, which stores a value into the ${MsgId} macro. The value stored is the phrase Illegal Message-Id: followed by the value of the offending Message-Id: header.
By defining the ${MsgId}, sendmail will add a new header to the message because of the mc file line:
H?${MsgId}?X-Authentication-Warning: ${MsgId}
If a message were to arrive with a bad Message-Id: header, such as the following:
Message-Id: <167445390329650300582-mailer.exe v1.2>
the preceding rules would cause the following new header to be added to the message:
X-Authentication-Warning: Illegal Message-Id: <167445390329650300582-mailer.exe v1.2>
Note that sendmail macros in header definitions do not need the $& prefix because macros used in header declarations are not processed when the configuration file is read. They are instead processed when the header declaration line is processed.
As a precaution, only store values into macros that you define. By storing values into sendmail's internally defined macros, you can easily corrupt the sendmail program's operation, with unforeseen results.
The inclusion of a header based on a macro's value is guaranteed to work only when mail is first sent or delivered, and can fail if the message is queued. Consider, for example, the desire to include a header that prints one of the sendmail program's macro values:
LOCAL_CONFIG H?${dsn_envid}?X-ENVID: ${dsn_envid}
The intention here is to record the value of the DSN envelope identifier value in an X- header, if such an identifier was supplied during the SMTP transaction. If a message is received with a MAIL FROM: line such as the following, the envelope identifier and ${dsn_envid} macro's value will be given the text following the ENVID= expression:
MAIL FROM: <bob@some.domain> ENVID=1234abcd5678
When this message is received, the ${dsn_envid} macro will contain a value (the string 1234abcd5678) which will cause the X-ENVID: header to be given a value:
X-ENVID: 1234abcd5678
If this message cannot be delivered right away and is deferred to the queue instead, the previous header will be stored in the queue like this:
H?${dsn_envid}?X-ENVID: 1234abcd5678
Note that the original mc file's ?${dsn_envid}? test is included in the queue file. When this message is later delivered, the ${dsn_envid} macro will not have a value. That macro is given a value only when the message is first received with SMTP. As a consequence, when the message is delivered from the queue, the ${dsn_envid} macro will lack a value and thus the X-ENVID: header will not be included in the delivered message.
If you need to base header inclusion on such macros, you should add the macro's name to the $={persistentMacros} class ($={persistentMacros}) to ensure that the macro's value survives the queue process. Using this solution, the previous mc file declaration will instead look like this:
LOCAL_CONFIG H?${dsn_envid}?X-ENVID: ${dsn_envid} C{persistentMacros} {dsn_envid}
Macros saved in the $={persistentMacros} class will have their values saved when the message is queued and restored when the message is delivered from the queue.
Note, however, that the $={persistentMacros} class can be dangerous. To be safe, avoid adding any of sendmail's internally defined macros to this class.