The syntax of policy

Comments

Any charactors between “/*” and “*/” are ignored.

Any charactors between “//” and the end of line are ignored.

SMTP Command blocks

The RPF policy consists of the following four SMTP Command blocks:

connect { ... }
mail_from { ... }
header { ... }
body { ... }

“header” and “body” corresponds to the SMTP DATA Command.

Statements

Each block should have one or more statements. Statements must be terminated by “;”.

The minimum statement is action itself. There are five actions:

accept
Accept the message with 250.
discard
Accept the message with 250 but silently discard it.
reject
Reject the message with 5xx.
hold
Temporarily reject the message with 4xx.
continue
Go to the next block.

Here is a meaningless example:

connect {
    accept;
}

All messages are accepted when their SMTP connections are created and no further blocks will be evaluated.

Conditions

If action is followed by “:”, the rest of the line is a condition expression.

A condition expression is one of the followings:

keyword == comma-separated-literals
True if keyword is included in comma-separated-literals. Otherwise, false.
keyword != comma-separated-literals
True if keyword is not included in comma-separated-literals. Otherwise, false.

Here is an example to reject a message if the result of SPF is ‘softfail’ or ‘hardfail’:

    reject: #spf == softfail, hardfail;

Logical AND can also be used:

expression && expression
True if both expressions are true. Otherwise false.

Here is an example to reject a message if the domain part of the SMTP MAIL FROM is “example.com” and the DKIM field does not exist.

    reject: #mail_from == "example.com" && #sig_dkim == No;

Types and literals

Boolean

“Yes” means true while “No” indicates false.

Here is an example to accept a message if the DKIM field exists:

    accept: #sig_dkim == Yes;

Domain

String enclosed in the double quotes is a domain.

Here is an exapmle to reject a message if the domain part of the From field is “example.com”:

    reject: #from == "example.com";

IP address

You can use IPv4 and IPv6 numeric notation with an optional range.

Here is an exapmle to accept 127.0.0.1 and reject 2001:DB8::/32:

    accept: #ip == 127.0.0.1;
    reject: #ip == 2001:DB8::/32;

Results of domain authentication

Result values of domain authentication can be written as is.

You can specify one of ‘none’, ‘pass’, ‘fail’, ‘policy’, ‘neutral’, ‘temperror’, ‘permerror’, ‘nxdomain’, ‘unknown’, ‘discard’, ‘hardfail’, ‘softfail’.

Here is an example to hold a message if the result of SPF is ‘softfail’:

    hold: #spf == softfail;

Keywords

A keyword started with “#”.

The timing when each keyword become available is as follows:

// #ip
connect { ... }
// #spf, #mail_from
mail_from { ... }
// #from, #pra, #sender_id, #dkim_from, #domainkeys_from,
// #sig_dkim, #sig_domainkeys
header { ... }
// #dkim, #domainkeys
body { ... }

For example, “#ip” is the source IP address of SMTP connection. It is decided before the “connect” block is evaluated and all further blocks can use it.

#ip
IP address of an SMTP peer.
#mail_from
Domain part of SMTP MAIL FROM.
#from
Domain part of the From field.
#pra
Domain part of PRA.
#dkim_from
Domain of DKIM.
#domainkeys_from
Domain of DomainKeys.
#sig_dkim
Boolean on whether or not the DKIM-Signature field exist.
#sig_domainkeys
Boolean on whether or not the DomainKey-Signature field exist.
#spf
Result of SPF.
#sender_id
Result of Sender ID.
#dkim
Result of DKIM.
#domainkeys
Result of DomainKeys.

User defined constants

A name can be given to comma-separated-literals. A name starts with “$” and followed by alphabet or number or ’_’ or ‘-’.

A name can be defined in the top level with “=”.

Here is a example:

$ip_white_lists = 127.0.0.1, ::1;

connect {
    accept: #ip == $ip_white_lists;
}