DATA, MIME or DKIM ACLs for a message delivered by cutthrough routing.
More than one header can be removed at the same time by using a colon separated
-list of header names. The header matching is case insensitive. Wildcards are
-not permitted, nor is list expansion performed, so you cannot use hostlists to
+list of header specifiers.
+.new
+If a specifier does not start with a circumflex (^)
+then it is treated as a header name.
+The header name matching is case insensitive.
+If it does, then it is treated as a (front-anchored)
+regular expression applied to the whole header.
+
+&*Note*&: The colon terminating a header name will need to be doubled
+if used in an RE, and there can legitimately be whitepace before it.
+
+Example:
+.code
+remove_header = \N^(?i)Authentication-Results\s*::\s*example.org;\N
+.endd
+.wen
+
+List expansion is not performed, so you cannot use hostlists to
create a list of headers, however both connection and message variable expansion
are performed (&%$acl_c_*%& and &%$acl_m_*%&), illustrated in this example:
.code
warn message = Remove internal headers
remove_header = $acl_c_ihdrs
.endd
-Header names for removal are accumulated during the MAIL, RCPT, and predata ACLs.
+Header specifiers for removal are accumulated during the MAIL, RCPT, and predata ACLs.
Matching header lines are removed from the message before processing the DATA and MIME ACLs.
If multiple header lines match, all are removed.
There is no harm in attempting to remove the same header twice nor in removing
-a non-existent header. Further header lines to be removed may be accumulated
-during the DATA and MIME ACLs, after which they are removed from the message,
-if present. In the case of non-SMTP messages, headers to be removed are
-accumulated during the non-SMTP ACLs, and are removed from the message after
+a non-existent header. Further header specifiers for removal may be accumulated
+during the DATA and MIME ACLs, after which matching headers are removed
+if present. In the case of non-SMTP messages, remove speifiers are
+accumulated during the non-SMTP ACLs, and are acted on after
all the ACLs have run. If a message is rejected after DATA or by the non-SMTP
ACL, there really is no effect because there is no logging of what headers
would have been removed.
11. An option for the ${readsocket } expansion to set an SNI for TLS.
+ 12. The ACL remove_header modifier can take a pattern.
+
Version 4.96
------------
add_header = :at_start:${authresults {<admd-identifier>}}
Note that it would be wise to strip incoming messages of A-R headers
- that claim to be from our own <admd-identifier>.
+ that claim to be from our own <admd-identifier>. Eg:
+
+ remove_header = \N^(?i)Authentication-Results\s*::\s*example.org;\N
There are four new variables:
*/
BOOL
-header_testname(header_line *h, const uschar *name, int len, BOOL notdel)
+header_testname(const header_line * h, const uschar * name, int len,
+ BOOL notdel)
{
uschar *tt;
if (h->type == '*' && notdel) return FALSE;
-if (h->text == NULL || strncmpic(h->text, name, len) != 0) return FALSE;
+if (!h->text || strncmpic(h->text, name, len) != 0) return FALSE;
tt = h->text + len;
while (*tt == ' ' || *tt == '\t') tt++;
return *tt == ':';
header_testname() above. */
BOOL
-header_testname_incomplete(header_line *h, const uschar *name,
+header_testname_incomplete(const header_line * h, const uschar * name,
int len, BOOL notdel)
{
if (h->type == '*' && notdel) return FALSE;
-if (h->text == NULL || strncmpic(h->text, name, len) != 0) return FALSE;
+if (!h->text || strncmpic(h->text, name, len) != 0) return FALSE;
return TRUE;
}
extern void header_add(int, const char *, ...);
extern void header_add_at_position(BOOL, uschar *, BOOL, int, const char *, ...);
extern void header_remove(int, const uschar *);
-extern BOOL header_testname(header_line *, const uschar *, int, BOOL);
-extern BOOL header_testname_incomplete(header_line *, const uschar *, int, BOOL);
+extern BOOL header_testname(const header_line *, const uschar *, int, BOOL);
+extern BOOL header_testname_incomplete(const header_line *, const uschar *, int, BOOL);
extern void log_write(unsigned int, int, const char *format, ...) PRINTF_FUNCTION(3,4);
extern int lss_b64decode(uschar *, uschar **);
extern uschar *lss_b64encode(uschar *, int);
*/
static void
-add_acl_headers(int where, uschar *acl_name)
+add_acl_headers(int where, uschar * acl_name)
{
-header_line *last_received = NULL;
+header_line * last_received = NULL;
switch(where)
{
for (header_line * h = header_list; h; h = h->next) if (h->type != htype_old)
{
- const uschar * list = acl_removed_headers;
+ const uschar * list = acl_removed_headers, * s;
int sep = ':'; /* This is specified as a colon-separated list */
- uschar *s;
+ /* If a list element has a leading '^' then it is an RE for
+ the whole header, else just a header name. */
while ((s = string_nextinlist(&list, &sep, NULL, 0)))
- if (header_testname(h, s, Ustrlen(s), FALSE))
+ if ( ( *s == '^'
+ && regex_match(
+ regex_must_compile(s, MCS_CACHEABLE, FALSE),
+ h->text, h->slen, NULL)
+ )
+ || header_testname(h, s, Ustrlen(s), FALSE)
+ )
{
h->type = htype_old;
- DEBUG(D_receive|D_acl) debug_printf_indent(" %s", h->text);
+ DEBUG(D_receive|D_acl) debug_printf_indent(" %s", h->text);
}
}
acl_removed_headers = NULL;
remove_header = x-data-2
warn log_message = Verified removed header X-Data-3 in this ACL still visible
condition = ${if !eq{$h_x-data-3:}{}}
+ warn remove_header = \N^(?i)Authentication-Results\s*::\s*remove.org;\N
accept
notsmtp:
X-NotSMTP-1: Line twenty-one
X-NotSMTP-2: Line twenty-two
X-NotSMTP-3: Line twenty-three
+Authentication-Results: keep.org; baz barf
+Authentication-Results: keep.org;
+ multiline
Message-Id: <E10HmaX-0005vi-00@myhost.test.ex>
From: mailok@test.ex
Date: Tue, 2 Mar 1999 09:44:33 +0000
X-NotSMTP-1: Line twenty-one
X-NotSMTP-2: Line twenty-two
X-NotSMTP-3: Line twenty-three
+Authentication-Results: remove.org; foo bar
+Authentication-Results: keep.org; baz barf
+authentication-Results : REMOVE.ORG;
+ foo bar multiline
+Authentication-Results: keep.org;
+ multiline
Test message
.