Configuration File
- Table of Contents
- Overview
- Grouping Contexts
- Configuration Hooks
-
Configuration Directives
- Core Directives
- System Options
- VirtualMTAs
- Database Connections
- DKIM Keys
- URL Domains
- Incoming Email Domains
- Throttle Programs
- Mail Classes
- Engine Users
- Performance Tuning
- SMTP Delivery
- Logging
- Message Processing
- Legacy
- System Monitoring
- TLS Certificates
- GreenArrow Marketing Studio
- Event Processing
- Event Delivery
- Syntax Checker
- Reload Configuration in Active Services
- Dynamic Defaults
- Review Per-Domain Configuration
- Example File
Overview
GreenArrow Engine originally used multiple configuration files,
one for each setting in the /var/hvmail/control
directory. Now,
as new features are added, new configuration parameters are added
as directives in /var/hvmail/control/greenarrow.conf
. Eventually,
all existing GreenArrow configuration files will be replaced with
directives in greenarrow.conf
, and it will serve as a single
master configuration file.
The greenarrow.conf
configuration file is a plain-text file (using
UTF-8) inspired by the
NGINX configuration file format.
A single directive inside of a grouping block looks like this:
general {
system_max_smtp_connections 5000
}
Some blocks have parameters. For example, this applies a configuration to the “yahoo.com” domain name:
domain yahoo.com {
reuse_connections yes
}
All lines whose first non-whitespace character is a pound sign (#
) are
treated as comments.
String Encoding
Raw encoding
String values that consist of only letters (a-zA-Z
), numbers (0-9
), dashes
(-
), underscores (_
), plus signs (+
), periods (.
), asterisks (*
),
slashes (/
), backslashes (\
), square brackets ([
and ]
), dollar signs
($
), colons (:
), semicolons (;
), percentages (%
), vertical bars (|
),
and at-signs (@
) do not require quotation.
All other string values must be surrounded by quotation marks ("
) or backticks.
Double quoted strings
Strings may be surrounded by quotation marks ("
) and may
contain the same escape codes as JSON string values.
The escape codes are:
\" |
Quotation mark |
\\ |
Backslash |
\/ |
Slash |
\b |
Backspace |
\f |
Formfeed |
\n |
Newline |
\r |
Carriage return |
\t |
Horizontal tab |
\uNNNN |
Four hexadecimal digits representing a Unicode codepoint |
Backtick strings
Strings can also be entered using backticks. When using this syntax, no characters can be escaped. This is useful for entering strings that contain double-quotes or backslashes that might require excessive escaping in a double-quoted string.
Backtick strings may span multiple lines, if needed.
File load strings
String values can have their content loaded from a file. This is done using the
<FILENAME>
syntax. FILENAME
must be an absolute file path (meaning it must
begin with a forward slash /
).
Here are some examples:
general {
postgres_custom_config </var/hvmail/etc/postgres_custom.conf>
}
In the case above, when greenarrow_config reload
is run, the content that is
currently in /var/hvmail/etc/postgres_custom.conf
will be provided as the
first argument to the general.postgres_custom_config
directive.
Heredocs
Heredocs are a special string syntax designed to make it easy to embed longer text into a string.
Heredocs consist of three parts:
- The opening anchor:
- This is defined on the same line as the directive.
- This always starts with
<<
, then consists of letters (a-zA-Z
), numbers (0-9
), underscores (_
), and dashes (-
). - After the opening anchor the parsing of the configuration line continues normally.
- The content of the heredoc:
- The content begins on the first line following the line with the opening anchor.
- This can consist of any characters, so long as it does not contain the anchor on its own on a line.
- The terminating anchor:
- This is the same string as set in the opening anchor, without the leading
<<
. - The terminating anchor exists on its own line.
- The terminating anchor may include leading and trailing whitespace.
- This is the same string as set in the opening anchor, without the leading
When greenarrow_config reload
parses a heredoc, it checks the first line of
the content for leading whitespace. This same leading whitespace is removed
from each subsequent line (if present). This means that in the example below,
only the maintenance_work_mem
line will have leading whitespace (in this
case, 2 spaces). If a line does not include leading whitespace (or includes
insufficient leading whitespace), whatever leading whitespace the line has will
be used unchanged.
general {
example_directive <<PG_CONF
shared_buffers = 30GB
effective_cache_size = 60GB
work_mem = 1GB
maintenance_work_mem = 8GB
PG_CONF
}
Heredocs can be treated as one of multiple arguments in a directive.
general {
example_directive_with_multiple_arguments first-argument <<SECOND-ARGUMENT `third-argument`
here is the content of the second argument
SECOND-ARGUMENT
}
Multiple heredocs may be started on the same line. When this is done, the heredoc content and terminating anchors must appear in the order that the heredocs are opened on the first line.
general {
example_directive_with_two_arguments <<FIRST <<SECOND
content of the first argument
might include multiple lines
FIRST
content of the second argument
can also include multiple lines
SECOND
}
Combining Strings
Strings that are next to each other (with no whitespace between them) will be combined.
For example, this directive will be set to abcde
:
directive a`b`"c"d`e`
This example, the directive will be set to message=This is my message
(which is useful for
directives that accept named arguments):
directive message="This is my message"
Examples
The following are all valid string values:
example
example.com
other-example123
other_example.900
5000.12
09000
"example with spaces"
"example\nwith\ncontrol\codes\n"
`example`
`example with spaces`
`example with "double-quotes" and \backslashes\`
`example with
a newline
or two in it`
Regular Expression Encoding
Regular expressions may be entered delimited by forward slashes.
For example:
ip_address * {
domain * {
override_smtp_result /over quota/ perm_failure case_insensitive=yes
override_smtp_result /over\/quota/ perm_failure case_insensitive=yes
}
}
When delimiting a regular expression by forward slashes, the only escape codes recognized when
looking for the closing forward slash are \\
and \/
. These escape codes are not resolved,
meaning that the characters between the forward slashes are passed direclty to the regular
expression engine (which will interpret the escape codes itself). Forward slash delmited regular
expressions may not contain a newline.
This syntax is unlike programming languages in that it does not support flags
following the regular expression (for example, /over quota/i
is not a valid
regular expression in this configuration file).
To apply a regular expression flag such as s
, use the (?s)
syntax such as
/(?s)over quota.*try again/
.
Strings as regular expressions:
Regular expressions may also be entered using standard string encoding or backtick string encoding. For example, these three directives are all the same:
override_smtp_result /over quota/ perm_failure
override_smtp_result "over quota" perm_failure
override_smtp_result `over quota` perm_failure
When using standard string encoding the string escape codes are resolved before passing data to the regular expression engine. For example, these three directives all have the same regular expression:
override_smtp_result /over\s+quota/ perm_failure
override_smtp_result `over\s+quota` perm_failure
override_smtp_result "over\s+quota" perm_failure
The regular expression syntax used is that understood by the Go programming language. While this is mostly a subset of PCRE, there may be a few differences. Please refer to the Go documentation for help with regular expression syntax, or contact technical support.
Boolean Encoding
Booleans may be specified as yes
or no
.
Duration Encoding
A time interval (referred to in this document as a “duration”) may be specified
as a sequence of decimal numbers, each with a unit suffix. For example 25h
, 300s
,
or 4h15m
.
Valid suffixes are s
, m
, h
, and d
.
Localpart Encoding
The localpart is the portion of an email address that appears before the @
sign. For example, the localpart of [email protected]
is user
.
Studio’s Subscriber Record documentation
goes into detail on what is valid in a localpart.
Localparts are encoded using the same rules as strings.
Option Flags Encoding
Some directives accept a list of option flags. These flags are sometimes predefined (for example event_delivery_events) while other directives have options that you define (for example event_delivery_filter_mail_class).
The syntax for these options is:
- Any string syntax can be an option (see the various string encodings documented above).
- The option is separated at its first equal sign (
=
). - The part of the string the precedes the first equal sign is the option flag key.
- The part of the string that follows the first equal sign is the option flag value.
- Commas separating the option flags are optional.
Boolean option flags have the additional attributes:
- The value must either be blank (i.e. no equal sign is present, or the part
after the equal sign is blank) or the value must be a valid boolean value
(
yes
orno
). - Option flag values that are blank are treated as
yes
.
Here are examples of valid boolean option flags:
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_filter_mail_class `mc_a` mc_b "mc_c=yes", mc_d=yes
}
Context Layering
If multiple contexts declare the same identifier, those contexts will be “layered” together. This means that:
- For directives that set a value, the later definition would be used.
- For directives that stack or create a list, the definitions will be merged.
For example, given the following configuration:
ip_address ipaddr-1 {
domain example.com {
max_concurrent_connections 100
override_smtp_result /over quota 1/ success case_insensitive=yes
}
domain example.com {
max_concurrent_connections 200
override_smtp_result /over quota 2/ success case_insensitive=yes
}
}
The configuration that is used by GreenArrow for the above is identical to this:
ip_address ipaddr-1 {
domain example.com {
max_concurrent_connections 200
override_smtp_result /over quota 1/ success case_insensitive=yes
override_smtp_result /over quota 2/ success case_insensitive=yes
}
}
This is because max_concurrent_connections is a single value that is overwritten by the second occurrence, whereas override_smtp_result can be specified multiple times.
Grouping Contexts
The greenarrow.conf
configuration file is organized hierarchically as
described below:
This top-level group contains settings that do not belong in any other group.
This grouping contains settings that are specific to one or more IP addresses.
This configuration grouping does not create an IP address VirtualMTA unless
define_virtual_mtas_in_config_file is yes
. Rather it applies
settings to existing IP address VirtualMTAs and the ip_address_name must
case-insensitively match the name of an
IP address VirtualMTA
configured through the web-interface or API.
The argument to this directive must be the IP address name – specifying a database ID is not supported.
The special IP address of a single asterisk (*
) means
that this context block defines settings that apply to all IP
addresses in the system. Records defined for a specific IP address
name take precedence over records defined for the wildcard
*
IP address.
The special IP address of **super**
means that this context block overrides
all other settings specified elsewhere in the system. No other settings
take higher priority than those in the **super**
block. This applies both
to mail delivered through an IP or delivered through a relay server.
For example:
ip_address smtp2, smtp3 {
...
}
ip_address * {
...
}
ip_address **super** {
...
}
This grouping contains settings that are specific to one or more SMTP relay servers.
This configuration grouping does not create a relay server unless
define_virtual_mtas_in_config_file is yes
. Rather it applies
settings to existing relay server VirtualMTAs and the relay_server_name must
case-insensitively match the name of a
relay server
configured through the web-interface or API.
For example:
relay_server esp1, esp2 {
...
}
Wildcard (*
) relay server configurations are not supported.
This context exists within an IP address (including the *
wildcard entry and
**super**
override). It contains settings for one or more recipient email
address domain. Specifying an *
indicates that the settings shall be used as
the default for any remote domain that does not otherwise contain a particular setting.
Domains can be defined with the following wildcards:
- A domain that is prefixed with
[*.]
matches the given domain and all subdomains. For example,[*.]example.com
matchesexample.com
,subdomain.example.com
, andwww.subdomain.example.com
. - A domain that is prefixed with
*.
matches only subdomains. For example,*.example.com
matchessubdomain.example.com
andwww.subdomain.example.com
, but will not matchexample.com
.
Domains can also be MX hostnames, specified like mx:mx1.example.com
. When
specified as an MX, throttling is performed based upon the resolved MX
hostnames of the recipient’s domain. If any resolved MX record matches an
mx:___
entry, that entry’s throttling configuration will be used. This search
is performed in MX priority order.
On the **super**
IP address, domain can also be specified as an IP address like a:1.2.3.4
.
If a recipient domain has no configured MX records, the recipient domain (and
its IP address) itself will be used for mx:
and a:
matching.
Settings to use for a domain are checked in this order. The first match is used:
- The
**super**
IP record, exact recipient domain. - The
**super**
IP record, wildcard recipient domain. - The
**super**
IP record, exact match of MX domain (mx:mx1.example.com
). - The
**super**
IP record, wildcard match of MX domain. - The
**super**
IP record, match of an MX IP address (a:1.2.3.4
). - The
**super**
IP record, wildcard domain (*
). - An exact IP name match, exact match of recipient domain.
- An exact IP name match, wildcard match of recipient domain.
- An exact IP name match, exact match of MX domain.
- An exact IP name match, wildcard match of MX domain.
- An exact IP name match, wildcard domain (
*
). - The
*
IP record, exact match of recipient domain. - The
*
IP record, wildcard match of recipient domain. - The
*
IP record, exact match of MX domain. - The
*
IP record, wildcard match of MX domain. - The
*
IP record, wildcard domain (*
).
For example, when looking up delivery to foo.example.com
(with an mx of mx1.example.com
) domain strings are searched for in the following order:
foo.example.com
[*.]foo.example.com
*.example.com
[*.]example.com
*.com
[*.]com
mx:mx1.example.com
mx:*.example.com
mx:[*.]example.com
mx:*.com
mx:[*.]com
*
All name or domain matches are case-insensitive.
If define_virtual_mtas_in_config_file is enabled, the wildcard *
may
not be combined with any other domain names or wildcards.
ip_address ipaddr-1, ipaddr-2 {
domain yahoo.com, ymail.com {
...
}
}
ip_address * {
domain hotmail.com {
...
}
domain gmail.com, googlemail.com {
...
}
domain * {
...
}
}
This context defines a Routing Rule.
The define_virtual_mtas_in_config_file directive must be enabled for this context to take effect.
routing_rule my-routing-rule-name {
...
}
This context defines a domain rule within a Routing Rule.
The define_virtual_mtas_in_config_file directive must be enabled for this context to take effect.
Each routing_rule
is required to have at least a routing_rule_domain
for the *
domain.
The wildcard *
may not be combined with any other domain names or wildcards.
routing_rule my-routing-rule-name {
routing_rule_domain first.example.com, second.example.com, third.example.com {
routing_rule_destination foo
}
routing_rule_domain alpha.example.com, beta.example.com {
routing_rule_destination bar
}
routing_rule_domain * {
routing_rule_destination baz
}
...
}
This context is for configuration directives that apply to an email based off
of the VirtualMTA name used to inject the message. This is the
VirtualMTA name provided in the X-GreenArrow-VirtualMTA
header or
the GREENARROW_MTAID
environment variable. This is not necessarily
the same as the IP Address or Relay Server used to deliver the message.
For example, in the case where:
- An email is injected with the VirtualMTA name of
shared_pool
-
shared_pool
is a Routing Rule that splits email throughip_a
andip_b
- The actual email delivery is done on
ip_a
These settings apply:
-
virtual_mta_injected "shared_pool" { }
- This matches the injected VirtualMTA name of
shared_pool
.
- This matches the injected VirtualMTA name of
-
virtual_mta_injected "*" { }
- This is the default and, unless overridden by a more precise directive, applies to all messages.
-
ip_address "ip_a" { }
- This is the IP on which the email was delivered.
These settings will not apply:
-
virtual_mta_injected "ip_a" { }
- The message was injected on
shared_pool
, notip_a
.
- The message was injected on
-
ip_address "shared_pool" { }
- The message was delivered on
ip_a
, notshared_pool
.
- The message was delivered on
All name matching is case-insensitive.
If email is injected using the numeric primary key of an IP Address, Relay Server, or Routing Rule, then a virtual_mta_injected block with a name matching the name of the IP Address, Relay Server, or Routing Rule is used.
virtual_mta_injected smtp-1, smtp-2 {
...
}
This context defines a Database Connection.
The define_database_connections_in_config_file directive must be enabled for this context to take effect.
database_connection my-database-name {
...
}
This context defines what DKIM keys are available for the specified domains.
The define_dkim_keys_in_config_file directive must be enabled for this context to take effect.
This context does not support wildcard domains.
dkim_domain example.com, example.net {
dkim_key ga "/etc/my-keys/ga.pem" default=yes
dkim_key my-selector "/etc/my-keys/my-selector.pem"
...
}
This context defines what URL domains are available.
The define_url_domains_in_config_file directive must be enabled for this context to take effect.
This context does not support wildcard domains.
url_domain example.com, example.net {
use_ssl yes
}
This context defines what incoming email domains and mailboxes are available.
The define_incoming_email_domains_in_config_file directive must be enabled for this context to take effect.
Each block supports a single incoming email domain. Any additional domains which you wish to use the same configuration should be specified using the domain_aliases directive.
This context does not support wildcard domains.
incoming_email_domain example.com {
domain_aliases example.net, example.org
...
}
This context defines a mailbox that is authorized to use SMTP AUTH and POP3.
Each block supports a single mailbox. The mailbox_is_wildcard directive allows for wildcards.
incoming_email_domain example.com {
user_mailbox newsletter {
mailbox_delivery_mode local
...
}
}
This context defines a forwarding mailbox.
Each block supports a single mailbox. The mailbox_is_wildcard directive allows for wildcards.
incoming_email_domain example.com {
forwarding_mailbox newsletter {
mailbox_forward_to "[email protected]"
...
}
}
This context defines the configuration for a Throttle Program.
The define_throttle_programs_in_config_file directive must be enabled for this context to take effect.
Each block supports a single throttle program.
throttle_program warmup {
backoff_max_concurrent_connections 10%
....
}
This context defines the configuration for a Mail Class.
The define_mail_classes_in_config_file directive must be enabled for this context to take effect.
Each block supports a single Mail Class.
Here’s an example mail class with everything enabled (Bounce & FBL Handling, Click & Open Tracking, Message-ID, List-Unsubscribe Headers, Unsub Links):
mail_class everything {
listid t1
virtual_mta smtp-1
handle_bounce_and_fbl yes
track_clicks_and_opens yes
add_message_id_if_missing yes
auto_list_unsubscribe_header yes
manage_unsubscribe_links yes
}
Here’s an example mail class with nothing enabled (some of these are enabled by default, so it’s important to be explicit with the behavior you want enabled/disabled):
mail_class nothing {
listid t1
virtual_mta smtp-1
handle_bounce_and_fbl no
track_clicks_and_opens no
add_message_id_if_missing no
auto_list_unsubscribe_header no
manage_unsubscribe_links no
}
Settings may also be placed into a wildcard *
block to apply to all mail classes (these settings can then be overwritten on individual mail classes):
mail_class * {
listid t1
virtual_mta smtp-1
handle_bounce_and_fbl no
track_clicks_and_opens no
add_message_id_if_missing no
auto_list_unsubscribe_header no
manage_unsubscribe_links no
}
# This mail class will simply inherit all of the defaults defined in
# the * block above.
mail_class default
# This mail class will also have the defaults, but with a distinct listid.
mail_class with_override {
listid t2
}
This context defines the configuration for an engine user account. The define_engine_users_in_config_file directive must be enabled for this context to take effect.
Each block defines a single user account.
The following directives are required for all engine_user entries:
Additionally, the following directives are optional:
engine_user "[email protected]" {
engine_user_password "my-secret-password"
engine_user_permission injection=smtp-only api=stats-only ui=read-only
}
This context groups directives that are specific to the IP address of the host that injected the message into GreenArrow.
The IP can be one or more of the following:
- Specific IP addresses (e.g.
127.0.0.1
) - CIDR IP address notation (e.g.
192.0.2.0/24
,10.0.0.0/8
) - Wildcard
*
to match all IP addresses
Source directives will be evaluated from most-specific to least-specific. This means that a source that specifies a single IP address will match before a CIDR range, which in turn will match before the wildcard.
CIDR ranges are normalized for purposes of configuration and evaluation. This means:
- An entered source of
192.168.1.99/24
will be normalized to192.168.1.0/24
. - An entered source of
*
or0/0
will be normalized to0.0.0.0/0
. - An entered source of
10.0.2.4
will be normalized to10.0.2.4/32
.
If you have a configuration error, the error message will reference the normalized CIDR range.
Most messages injected into GreenArrow have a source IP. Messages injected on the
command-line by tools like mailsubj
do not. Messages that do not have a source
IP will only be matched by the wildcard *
source.
source * {
...
}
source 127.0.0.1, 192.0.2.0/24 {
...
}
Configuration Hooks
Configuration Hooks provide ways to add custom code to various parts of GreenArrow.
This directive accepts three parameters: the hook name, the programming language to use for the hook, and the code for the hook.
See Configuration Hooks for details on what hooks are available.
Configuration Directives
Directives are configuration settings that apply a specific option within a context.
Core Directives
This directive creates a macro that may be referenced from the strings/domains provided to a domain directive. See the example below to see how they are used.
domain_macro google gmail.com, googlemail.com
domain_macro microsoft msn, hotmail
domain_macro yahoo yahoo, ymail, rocketmail
domain_macro tlds com, net
ip_address * {
domain $google {
...
}
domain $microsoft.com {
...
}
domain $yahoo.$tlds {
...
}
}
The above example expands to the equivalent configuration below.
ip_address * {
domain gmail.com, googlemail.com {
...
}
domain msn.com, hotmail.com {
...
}
domain yahoo.com, yahoo.net, ymail.com, ymail.net, rocketmail.com, rocketmail.net {
...
}
}
Domain macros must be defined before they are used. If a macro’s definition is changed later in a configuration file, the new definition is used for subsequent directives.
This directive includes the given file to be parsed as part of the configuration file. This is useful for separating complex configurations into multiple files.
The filename given must be an absolute path (i.e., it must begin with /
).
This directive can be specified at either the top-level or within any context. If specified within a context, the specified include file will be included into that context.
include /usr/local/etc/ga/ip_addresses.conf
include /usr/local/etc/ga/general.conf
System Options
Set the maximum number of sends that can be aggregated by the Sends screen “Show aggregated statistics” option.
Excessively large values might cause the aggregated send reporting page to timeout.
general {
engine_send_aggregation_limit 5000
}
This directive specifies the time zone that should be used by GreenArrow Engine. This time zone applies to both the Engine user interface and when determining the default sendid to use for SimpleMH.
To get a list of available time zones, run the command greenarrow
list_known_time_zones
. This will print the time zones that are available on
your system – this is the common set of time zones from the system database,
the Ruby programming language, and the PHP programming language.
If you’re only interested in United States time zones, the command accepts an
argument to filter to just those greenarrow list_known_time_zones --us-only
.
If this directive is not specified, GreenArrow will attempt to determine the system time zone from the following sources:
- If
/etc/localtime
is a symlink to a time zone file, GreenArrow will use this time zone if it is one supported in the common set described above. - If the command
timedatectl
is available, GreenArrow will run this command to see if the time zone listed in its output is a supported time zone (not available on Docker). - Otherwise, GreenArrow will default to
UTC
.
If the legacy configuration $TIME_ZONE_OFFSET
is set in /var/hvmail/control/simplemh-config
is set, then it will supercede this directive for purposes of generating SimpleMH
per_instanceid_legacy
SendIDs. greenarrow_config validate
will warn you if this applies to you.
VirtualMTAs
When this directive is turned on, IP Addresses, Routing Rules, and Relay Servers in GreenArrow Engine’s internal database are replaced with those that are specified in the configuration file.
If this directive is enabled, default_virtual_mta must be specified.
general {
define_virtual_mtas_in_config_file yes
}
The VirtualMTA to use for delivery when none is specified.
This directive only takes effect if define_virtual_mtas_in_config_file is turned on. If it is, this directive must be specified.
general {
default_virtual_mta smtp1-1
}
The IP address and hostname to use for outgoing SMTP connections on this IP address.
- This may be not be specified on either the
*
or**super**
wildcard IP addresses. - This directive only takes effect if define_virtual_mtas_in_config_file is turned on.
- The smtp_source directive may not be combined with the smtp_source_hostname nor the smtp_source_ip directives.
This directive is a short way to write the two directives smtp_source_hostname and smtp_source_ip.
smtp_source_ip 127.0.0.1
smtp_source_hostname abc.com
The above is equivalent to:
smtp_source 127.0.0.1 abc.com
Unlike the other two directives, this directive can be specified multiple times, which acts as a short-hand for defining multiple IP addresses that act together as a “pool” and share the same settings.
When specified multiple times, the following behavior occurs:
- Instead of creating an IP address VirtualMTA named
${name}
(the name given to the ip_address directive), a routing rule VirtualMTA is created with that name.- That name must not already be assigned to a routing_rule.
- Each smtp_source directive results in an IP address named
${name}__${ip}
.- If there is a name conflict (because you’ve otherwise used the name
${name}__${ip}
), the first available numeric suffix such as_2
or_3
will be appended. - Each IP address created in this way will inherit the directives specified on the ip_address defined in the configuration file.
- If there is a name conflict (because you’ve otherwise used the name
- The routing rule VirtualMTA will deliver through each of the IP addresses created
above using randomization_type of
random
. Each IP address will receive the same portion of traffic.
Here’s an example of using the smtp_source directive to create a routing rule.
ip_address route-1 {
smtp_source 127.0.0.1 one.localhost
smtp_source 127.0.0.2 two.localhost
smtp_source 127.0.0.3 three.localhost
proxy_server 10.0.0.1:3030
domain * {
log_smtp_commands yes
}
}
The above is equivalent to:
routing_rule route-1 {
routing_rule_domain * {
routing_rule_destination route-1__127.0.0.1
routing_rule_destination route-1__127.0.0.2
routing_rule_destination route-1__127.0.0.3
randomization_type random
}
}
ip_address route-1__127.0.0.1 {
smtp_source 127.0.0.1 one.localhost
proxy_server 10.0.0.1:3030
domain * {
log_smtp_commands yes
}
}
ip_address route-1__127.0.0.2 {
smtp_source 127.0.0.2 two.localhost
proxy_server 10.0.0.1:3030
domain * {
log_smtp_commands yes
}
}
ip_address route-1__127.0.0.3 {
smtp_source 127.0.0.3 three.localhost
proxy_server 10.0.0.1:3030
domain * {
log_smtp_commands yes
}
}
The hostname to use for outgoing SMTP connections on this VirtualMTA.
This may not be specified on the *
wildcard IP address.
In the ip_address and relay_server contexts, this directive only takes effect if define_virtual_mtas_in_config_file is turned on. If it is, it then this directive must be specified for each ip_address and relay_server.
In the proxy_server context, this directive is always effective.
ip_address ip-address-1 {
smtp_source_hostname example.com
}
The IP address to use for outgoing SMTP connections on this VirtualMTA.
When not using proxy support, outgoing connections from GreenArrow will originate from this IP. When using proxy support (with the proxy_server directive), outgoing connections from the proxy will originate from this IP address.
This may not be specified on the *
wildcard IP address.
In the ip_address and relay_server contexts:
This directive only takes effect if define_virtual_mtas_in_config_file is turned on. If it is, it then this directive must be specified for each ip_address and relay_server.
In the proxy_server context:
This directive is always effective. It overrides the value specified for smtp_source_ip on the ip_address.
smtp_source_ip within the proxy_server context defines the IP address on the proxy from which you’d like SMTP delivery attempts to originate. Use proxy_server_local_bind to specify the IP address from which you’d like to connect to the proxy server.
ip_address ip-address-1 {
smtp_source_ip 127.0.0.101
}
These optional credentials are used as authentication for outgoing SMTP connections on this VirtualMTA.
This directive only takes effect if define_virtual_mtas_in_config_file
is
turned on.
relay-server my-relay-1 {
smtp_auth my-username my-password
}
In a domain
block inside of an ip_address
block, this specifies the
maximum number of total concurrent connections allowed to these domains
from this IP (as a group). If the domain block is for *
, then this
specifies the maximum number of concurrent connections allowed to any
individual domain that does not have a more specific rule.
In a relay_server
block this specifies the maximum number of total
concurrent connections allowed by the relay server.
This may be set to zero for no limit.
This directive only takes effect if define_virtual_mtas_in_config_file is turned on.
ip_address ip-address-1 {
# In the * wildcard case, any individual domain may have a total of 100 concurrent connections.
domain * {
max_concurrent_connections 100
}
# In this case, the two specified domains can jointly have a total of 500 concurrent connections.
domain first.example.com, second.example.com {
max_concurrent_connections 500
}
}
The maximum number of delivery attempts per unit of time allowed.
The denominator may be sec
, s
, min
, m
, hr
, or h
.
In a domain
block inside of an ip_address
block, this specifies the
rate allowed to these domains from this IP (as a group). If the
domain block is for *
, then this specifies the rate allowed to any
individual domain that does not have a more specific rule.
In a relay_server
block, this specifies the rate of delivery attempts
allowed by the relay server.
This directive only takes effect if define_virtual_mtas_in_config_file is turned on.
ip_address ip-address-1 {
# In the * wildcard case, any individual domain may send a total of 250 messages per hour.
domain * {
max_delivery_rate 250/hr
}
# In this case, the two specified domains can jointly send a total of 20 messages per second (72,000 messages per hour).
domain first.example.com, second.example.com {
max_delivery_rate 20/sec
}
}
The Throttle Program that should be used on the given domains for this VirtualMTA. The program is found by (case-insensitive) name.
This directive only takes effect if define_virtual_mtas_in_config_file
is
turned on.
ip_address ip-address-1 {
domain * {
throttle_program "automatic backoff"
}
}
Please be aware that the above example of a throttle_program on a *
domain
does not set a throttle_program on “all domains not otherwise specified”.
Instead, this provides a default value of throttle_program to all domain groups
that contain throttling directives (max_concurrent_connections and
max_delivery_rate). This is because
Throttle Programs only operate on explicitly
listed domain names.
This directive instructs GreenArrow to make outgoing SMTP connections using an intermediate proxy for SMTP deliveries from this IP address. This directive defines the hostname or IP of the proxy server to use. GreenArrow will make a request that the proxy server initiate a SMTP delivery connection from the smtp_source_ip of the IP address (or if a smtp_source_ip is configured for this proxy_server, that value will be used instead).
GreenArrow supports version 1 of HAProxy’s PROXY Protocol.
If multiple proxies are configured, GreenArrow will try to connect ot the first proxy server and if it cannot connect, it will try the second and continue through the list. If it cannot connect to any listed proxy, the message will be temporarily deferred.
See the Proxy Protocol documentation for more information.
This directive changes the definition of the “Sorry, I wasn’t able to establish an SMTP connection. (#4.4.1)” remote error message.
This directive also changes the behavior of remote timeouts.
The local IP address to use when connecting to a proxy server. Ordinarily, this does not need to be configured. However, if you know that you need to use a specific IP address in order to connect to your proxy server, GreenArrow provides this directive.
In this example, GreenArrow will attempt to connect to the proxy server 192.168.7.1:3030
with the local IP address 192.168.7.25
. If successful, it will start the proxy session
and attempt SMTP delivery using the IP address 1.2.3.4
.
ip_address * {
smtp_source_ip 1.2.3.4
smtp_source_hostname client.example.com
proxy_server 192.168.7.1:3030 {
proxy_server_local_bind 192.168.7.25
}
}
The destination to which email should be delivered by this VirtualMTA. If the percentage is not specified for one or more destinations, it is apportioned evenly from whatever is remaining from 100.
Percentage can be a floating point value with up to 7 decimal places of precision after the point.
Each routing_rule_domain
is required to have at least one child
routing_rule_destination
.
This directive only takes effect if define_virtual_mtas_in_config_file
is
turned on.
Limit on the number of destinations: We do not recommend adding or editing more than 10,000 destinations. While GreenArrow does not enforce a hard limit on the number of destinations, performance can suffer when exceeding this threshold.
routing_rule proxy-to-other-servers {
routing_rule_domain * {
# fastest-server will receive 50% of the messages
routing_rule_destination fastest-server 50%
# The remaining three servers will receive 16.66% of the messages each
routing_rule_destination slower-server-1
routing_rule_destination slower-server-2
routing_rule_destination slower-server-3
}
}
The method of randomization to the destinations. See the Routing Rule
documentation
for a more detailed explanation. The randomization type can be one of
random
, message_constant
, or email_address_constant
.
This directive only takes effect if define_virtual_mtas_in_config_file
is
turned on.
routing_rule proxy-to-other-servers {
routing_rule_domain * {
# fastest-server will receive 50% of the messages
routing_rule_destination fastest-server 50%
# The remaining three servers will receive 16.66% of the messages each
routing_rule_destination slower-server-1
routing_rule_destination slower-server-2
routing_rule_destination slower-server-3
randomization_type message_constant
}
}
This directive instructs GreenArrow to accept the X-Virtual-MTA
header. It
supports an optional directive on whether or not that header should be removed
from the message.
If this directive is enabled and remove
is not specified, the X-Virtual-MTA
header will be removed from messages.
When enabled, X-Virtual-MTA
is identical to and takes precedence over the
X-GreenArrow-MtaID
header.
general {
process_x_virtual_mta_header yes remove=no
}
Database Connections
When this directive is turned on, Database Connections in GreenArrow’s internal database are replaced with those specified in the configuration file.
general {
define_database_connections_in_config_file yes
}
The type of database to connect to. The following values are accepted:
postgres |
PostgreSQL |
mysql |
MySQL |
mssql |
Microsoft SQL Server |
This directive only takes effect if define_database_connections_in_config_file is turned on.
database_connection db {
database_type postgres
}
The hostname or IP address of the database server.
By default, GreenArrow connects to the following TCP ports:
postgres |
5432 |
mysql |
3306 |
mssql |
1433 |
If you would rather use a non-default port, add a :
suffix to the hostname
or IP address, followed by the desired port number. The following configuration
connects to db.example.com
on port 3000
:
database_connection db {
database_host db.example.com:3000
}
This directive only takes effect if define_database_connections_in_config_file is turned on.
The username to login to the database with.
This directive only takes effect if define_database_connections_in_config_file is turned on.
database_connection db {
database_username greenarrow
}
The password to login to the database with.
This directive only takes effect if define_database_connections_in_config_file is turned on.
database_connection db {
database_password secret
}
The name of the database to login to.
This directive only takes effect if define_database_connections_in_config_file is turned on.
database_connection db {
database_name crm
}
Whether GreenArrow should connect to the database server using a TCP port. This usually means that the database server is remote, but you can also set is_remote
to yes
, then connect to a local database server by connecting to 127.0.0.1
.
This directive only takes effect if define_database_connections_in_config_file is turned on.
database_connection db {
is_remote yes
}
Whether to enable TLS/SSL when connecting to the database server.
This directive only takes effect if define_database_connections_in_config_file is turned on.
database_connection db {
use_ssl yes
}
An optional string to append to the DSN used to connect to the database. All connections are made using Perl’s DBI interface.
This directive only takes effect if define_database_connections_in_config_file is turned on.
database_connection db {
extra_dsn_string "mysql_socket=/dev/mysql"
}
An optional description. GreenArrow stores this value but does not act upon it.
This directive only takes effect if define_database_connections_in_config_file is turned on.
database_connection db {
notes "CRM's MySQL server"
}
DKIM Keys
When this directive is turned on, DKIM keys in GreenArrow’s internal database are replaced with those specified in the configuration file.
general {
define_dkim_keys_in_config_file yes
}
selector |
The selector to use in the DKIM signature. |
private_key_filename |
Absolute path to a file containing a private key in PEM format. If the file cannot be read or parsed, it causes a validation error. |
default |
An optional parameter which controls whether this key/selector combination is used by default for signing mail for the domains listed in the parent |
Each instance of this directive defines a selector and private key to use for DKIM signing the parent domains’ email.
Each domain/selector combination may only appear once within the configuration file once. Duplicates cause validation errors.
GreenArrow extracts the public key from the private key that you provide. The public key must be at least 512 bits long to avoid validation errors. We recommend a minimum public key length of 1,024 bits.
An instance can be designated as the default for the parent domains. There can be only one default for any domain.
This directive only takes effect if define_dkim_keys_in_config_file is turned on.
DKIM keys specified with this directive are available to use by the X-GreenArrow-DKIM header.
See our DKIM keys doc for details on how GreenArrow decides on which DKIM keys to use for signing email.
dkim_domain example.com, example.net {
dkim_key ga "/etc/my-keys/ga.pem" default=yes
dkim_key my-selector "/etc/my-keys/my-selector.pem"
}
URL Domains
When this directive is enabled or absent:
HTTPS is always used when generating click, open, and unsubscribe tracking links.
GreenArrow recommends enabling this setting and url_domains_get_lets_encrypt_certs to avoid open image tracking tags breaking after this change in Google Chrome 81.
When this directive is disabled:
Each URL domain has its own use_ssl setting in greenarrow.conf
or
“SSL” checkbox in the web interface to
determine whether click, open, and unsubscribe links should be generated using
HTTP or HTTPS.
general {
url_domains_always_use_tls yes
}
This directive has no effect unless the Let’s Encrypt subscriber agreement has been accepted via lets_encrypt_agree_to_terms_of_service and lets_encrypt_registration_email.
When this directive is enabled or absent:
GreenArrow tries to automatically register TLS certificates with Let’s Encrypt and configure its HTTP Server to use them.
If a domain is configured in /var/hvmail/control/httpd.ssl.listen
following these instructions,
then Let’s Encrypt certificate isn’t used for that domain -
regardless of this directive’s setting. If the domain is removed from
that file, the Let’s Encrypt certificate is used.
GreenArrow recommends enabling this setting and url_domains_always_use_tls to avoid open image tracking tags breaking after this change in Google Chrome 81.
When this directive is disabled:
GreenArrow doesn’t attempt to register Let’s Encrypt TLS certificates automatically. Any Let’s Encrypt certificates that were previously registered remain on disk but aren’t used.
general {
url_domains_get_lets_encrypt_certs yes
}
When this directive is turned on, URL domains in GreenArrow’s internal database are replaced with those specified in the configuration file.
general {
define_url_domains_in_config_file yes
}
The default URL domain to be used for email sent from SimpleMH.
If you’re setting this to URL domain configured in GreenArrow, this value will be the bare domain name for that URL domain – this is the case most of the time. However, if you’re setting this value to a configured url_domain_external, then specify the entire URL as passed to url_domain_external.
The define_url_domains_in_config_file directive must be enabled for this directive to take effect.
If the legacy configuration $CLICKTHROUGH_URL
is set in /var/hvmail/control/simplemh-config
is set, then it will supercede this directive. greenarrow_config validate
will warn you if this applies to you.
general {
default_url_domain example.com
}
This directive is used to specify URLs on external servers which GreenArrow should consider valid when parsing the default_url_domain directive (or present it as a valid option when editing the default URL domain in Engine’s user interface).
URL domains hosted on the local GreenArrow server should not be listed using this directive.
It’s rare to need this directive. In most cases the default URL domain will
be a URL domain that has been configured into GreenArrow. This directive exists
to allow automatic conversion from legacy configurations where $CLICKTHROUGH_URL
was defined as an arbitrary value in /var/hvmail/control/simplemh-config
.
- Multiple URLs can be specified by providing a comma delimited list or
multiple
url_domain_external
directives. - The argument(s) passed to this directive must be a valid
http://
orhttps://
URL. - No other requirements are enforced for the format of this directive.
general {
url_domain_external "https://example.com/click"
url_domain_external "https://example.org/endpoint"
}
When this directive is turned on for the specified URL domain, or
url_domains_always_use_tls is turned on in the general
context,
click, open, and unsubscribe tracking URLs that use the specified URL domain
use HTTPS
. Otherwise, they use HTTP
.
url_domain example.com {
use_ssl yes
}
Incoming Email Domains
When this directive is turned on, incoming email domains and mailboxes in GreenArrow’s internal database are replaced with those specified in the configuration file.
general {
define_incoming_email_domains_in_config_file yes
}
The default bounce mailbox to be used for email sent from SimpleMH.
The define_incoming_email_domains_in_config_file directive must be enabled for this directive to take effect.
If the legacy configuration $RETURN_PATH_OVERRIDE
is set in /var/hvmail/control/simplemh-config
is set, then it will supercede this directive. greenarrow_config validate
will warn you if this applies to you.
general {
default_bounce_mailbox "[email protected]"
}
This directive lists one or more incoming email domains to
alias to the domain named
in the parent incoming_email_domain
directive. Aliased domains inherit all
of the delivery rules of the domain that they’re aliased to.
This directive controls how GreenArrow delivers mail to the domain. The options are:
normal |
Deliver email to the configured mailboxes. |
disabled |
Ignore this incoming email domain’s configuration. |
defer |
Defer deliveries to this domain. |
This directive lists the localparts of one or more bounce mailboxes.
This directive lists the localparts of one or more spam complaint mailboxes.
By default, mailboxes receive mail for localpart@
the given domain. If
mailbox_is_wildcard
is set to yes
, the mailbox also receives mail for
localpart-*@
the given domain, where *
expands to include any
characters allowed in an email address, other than the @
sign.
This directive causes email to be forwarded to the specified addresses. If there are multiple addresses to forward to, separate them with commas.
If this directive is used in a user_mailbox context,
mailbox_delivery_mode must be set to forward
or forward_and_local
.
This directive controls how mail that’s sent to a user_mailbox
gets
delivered. The options are:
local |
Deliver email to a local mailbox. The mail can be retrieved using POP3. |
forward |
Forward email to the address specified in mailbox_forward_to. |
forward_and_local |
Deliver two copies of each message - one using |
dotqmail |
Process incoming email according to the rules in a .qmail file. |
This directive is used to specify the contents of a .qmail file. See this document’s String Encoding section for how to enter a multiline file.
If this directive is used, mailbox_delivery_mode must be set to
dotqmail
.
This directive is used to specify the password that is used to login to a mailbox via SMTP or POP3.
If you don’t want to embed the raw password in greenarrow.conf
, see the
mailbox_password_encoded configuration directive instead.
This directive is used to specify the password that is used to login to a mailbox via SMTP or POP3.
This is an alternative to mailbox_password for cases where you don’t
want to embed the user’s password directly into greenarrow.conf
.
To generate an encoded password, use the greenarrow encode_mailbox_password
command like this:
$ greenarrow encode_mailbox_password mysecret
v1.c37f5859.519996598087b0c6798245b7c3415f83ea4bad03d4f4e46791221a486727de7d
$ greenarrow encode_mailbox_password --prompt
Enter password: <enter password first time>
Enter password (confirm): <confirm password>
v1.e882daca.e942a48c719cfca5af173827a1546f985a1408543743f7ed4bd20a7c96e19dd4
Then, take the encoded password and embed it into your configuration:
incoming_email_domain example.com {
user_mailbox username {
mailbox_delivery_mode local
mailbox_password_encoded "v1.c37f5859.519996598087b0c6798245b7c3415f83ea4bad03d4f4e46791221a486727de7d"
}
}
This directive controls whether the mailbox is locked. Locked mailboxes cannot authenticate using POP3 or SMTP, but can still receive mail.
Throttle Programs
When this directive is turned on, Throttle Programs in GreenArrow’s internal database are replaced with those specified in the configuration file.
general {
define_throttle_programs_in_config_file yes
}
This directive limits the maximum number of concurrent outgoing connections while in Backoff Mode.
The value may be either an integer for a fixed limit or a percentage of the maximum number of concurrent outgoing connections allowed when not in Backoff Mode:
- The minimum integer value is 1.
- Valid percentage values are 1% to 100%.
throttle_program warmup {
backoff_max_concurrent_connections 10%
}
This directive limits the maximum number of messages that may be sent per hour while in Backoff Mode.
The value may be either an integer for a fixed limit or a percentage of the maximum number of messages per hour allowed when not in Backoff Mode:
- The minimum integer value is 1.
- Valid percentage values are 1% to 100%.
throttle_program warmup {
backoff_max_messages_per_hour 10%
}
This directive sets the amount of time to stay in Backoff Mode once it begins. The value gets rounded up to the nearest time divisible by 5 minutes (10:00 am, 10:05 am, etc.), as described in the Throttle Programs documentation.
throttle_program warmup {
return_after 5m
}
This optional directive sets the minimum percentage of delivery attempts which must result in bounces (permanent failures) before Backoff Mode is entered.
The trigger_required_attempts threshold must also be met to enter Backoff Mode. The trigger_deferral_rate setting has no impact on this directive’s behavior.
throttle_program warmup {
trigger_failure_rate 10%
}
This optional directive sets the minimum percentage of delivery attempts which must result in deferrals or bounces (permanent failures) before Backoff Mode is entered.
The trigger_required_attempts threshold must also be met to enter Backoff Mode. The trigger_failure_rate setting has no impact on this directive’s behavior.
throttle_program warmup {
trigger_deferral_rate 50%
}
This directive sets the minimum number of delivery attempts that must have taken place in the past 5 minutes to enter Backoff Mode. The trigger_deferral_rate or trigger_failure_rate threshold must also be met to enter Backoff Mode.
The minimum value is 1.
throttle_program warmup {
trigger_required_attempts 100
}
Mail Classes
The following Mail Class attributes are not configuable via greenarrow.conf
or the configuration API. You may use
GreenArrow Engine’s web interface
to configure them:
- Regex Before HTML Conversion
- Regex After HTML Conversion
- Regex for HTML Part
- Regex for Text Part
All other Mail Class attributes are configurable via greenarrow.conf
.
When this directive is turned on, Mail Classes in GreenArrow’s internal database are replaced with those specified in the configuration file.
general {
define_mail_classes_in_config_file yes
}
This directive is used to specify bounce addresses on external servers which GreenArrow should consider valid when parsing the bounce_address setting for a Mail Class. Bounce mailboxes hosted on the local GreenArrow server should not be listed using this directive.
Multiple addresses can be specified by providing a comma delimited list or
multiple bounce_address_external
lines.
general {
bounce_address_external "[email protected]", "[email protected]"
bounce_address_external "[email protected]"
}
This directive sets the VirtualMTA used by a Mail Class.
mail_class orders {
virtual_mta smtp1-1
}
This directive sets the ListID used by a Mail Class.
mail_class orders {
listid widgets
}
This directive causes messages to be sent to the configured seed list once a day, starting at the first message number given, and ending at the second message number. For example, the following configuration would send to the seed list between the day’s 50th and 5,000th message:
mail_class orders {
seed 50 5000
}
This directive turns on or off click and open tracking for the Mail Class.
This can be overridden on a per-message basis using the X-GreenArrow-Click-Tracking-Do header.
mail_class orders {
track_clicks_and_opens yes
}
This directive turns on or off unsubscribe link tracking for the Mail Class.
mail_class orders {
manage_unsubscribe_links yes
}
This directive causes GreenArrow to save a copy of the first N messages each day to the PostgreSQL database. Use caution when setting this parameter because excessive use can lead to disk space exhaustion.
mail_class orders {
archive_sample_count 10
}
Each email should contain a Message-ID header so that the receiving email client can correctly process it. This directive causes GreenArrow to verify that the header exists in each email, and if not, to insert one.
mail_class orders {
add_message_id_if_missing yes
}
This directive controls the URL Domain to use for click and open tracking.
mail_class orders {
url_domain ga.example.com
}
This directive controls the bounce mailbox to use for messages in this Mail Class. The specified mailbox must be either:
- A local bounce mailbox configured via
greenarrow.conf
, the configuration API, or GreenArrow’s web interface. - Defined in a bounce_address_external directive.
mail_class orders {
bounce_address "[email protected]"
}
This directive controls whether GreenArrow will convert text only messages to HTML.
mail_class orders {
convert_textonly_to_html_do_conversion yes
}
This directive causes GreenArrow to append the specified footer to the HTML body of each text message that’s converted to HTML.
The directive only takes effect if
convert_textonly_to_html_do_conversion is set to yes
.
mail_class orders {
convert_textonly_to_html_header_to_add "<img src=c6848f7c280bb399662941f82611062fquot;https://example.com/logo.pngc6848f7c280bb399662941f82611062fquot;>"
}
This directive causes GreenArrow to append the specified footer to the HTML body of each text only that’s converted to HTML.
The directive only takes effect if
convert_textonly_to_html_do_conversion is set to yes
.
mail_class orders {
convert_textonly_to_html_footer_to_add "<img src=c11ce0cb108ec64fe59fe13cd1b7ea49quot;https://example.com/footer.pngc11ce0cb108ec64fe59fe13cd1b7ea49quot;>"
}
This directive causes the specified anchor text to be used in for links that appear in emails converted to HTML.
The directive only takes effect if
convert_textonly_to_html_do_conversion is set to yes
.
mail_class orders {
convert_textonly_to_html_link_text link
}
This directive causes GreenArrow to prepend the specified header to the HTML version of each message.
mail_class orders {
modify_html_header "<img src=ec1fffdf18a299f27fc18333aaec6e8dquot;https://example.com/logo.pngec1fffdf18a299f27fc18333aaec6e8dquot;>"
}
This directive causes GreenArrow to append the specified footer to the HTML version of each message.
mail_class orders {
modify_html_footer "<img src=969dc50e01e8825798e79b95b4983c99quot;https://example.com/footer.png969dc50e01e8825798e79b95b4983c99quot;>"
}
This directive causes GreenArrow to prepend the specified header to the text part of each multipart message.
mail_class orders {
modify_text_header "Thank you for your recent order.\n"
}
This directive causes GreenArrow to append the specified footer to the text part of each multipart message.
mail_class orders {
modify_text_footer "\nTo track your shipment, please login to https://example.com/"
}
When set to yes
, this directive causes each bounce message for the Mail
Class to be delivered to both the Mail Class’s configured
bounce_address and the bounce address that was set for the message
before it was injected into GreenArrow.
When set to no
, each bounce message is delivered to just the Mail Class’s
configured bounce_address.
mail_class orders {
bounce_message_passthrough yes
}
This directive causes SimpleMH to BCC a copy of every message in the Mail Class to the specified email address.
mail_class orders {
bcc "[email protected]"
}
This directive adds the specified email headers to each message. Headers must follow the following rules:
- If you specify multiple headers, separate them by newlines. Both Unix and Windows-style newlines are supported.
- Up to 1024 characters of custom headers are supported.
- Only the following
X-GreenArrow-*
headers are supported:X-GreenArrow-DKIM-Only-Using-Domain
X-GreenArrow-Signing-Selector
X-GreenArrow-Signing-Key-Filename
X-GreenArrow-DKIM
- The
X-Mailer-Info
header is prohibited. - Any other well-formed email headers are permitted.
mail_class orders {
add_email_headers "X-foo: bar\nX-bar: baz"
}
This option instructs GreenArrow to modify the email message so that the Bounce Processor is able to process bounces and spam complaints for messages using this Mail Class.
If you are using the Lite Bounce Processor, you will typically want this option to be disabled.
When handle_bounce_and_fbl
is enabled (which is the default) (or the header X-GreenArrow-HandleBounceAndFbl
is enabled), messages sent from this mail class will be affected in the
following ways so that GreenArrow’s non-lite bounce and FBL processor can process the messages:
- The 5321.MailFrom (
MAIL FROM
/Return-Path
) address will be overwritten so that GreenArrow receives and processes bounces resulting from these messages. - An
X-Mailer-Info
header will be added to these messages to aid in complaint processing and identification. - An
X-Mailer-Info-Extra
header will possibly be added to aid in bounce processing. - The automatically generated
List-Unsubscribe
header will include amailto:
option (instead of only the HTTP option). Thismailto:
option is a variant of GreenArrow’s 5321.MailFrom address indicating the message represents an unsubscribe.
When this setting is disabled, the above behaviors will not be in effect.
This can be overridden on a per-message basis using the X-GreenArrow-HandleBounceAndFbl header.
mail_class default {
handle_bounce_and_fbl no
}
The define_mail_classes_in_config_file directive must be enabled for this context to take effect.
This directive configures the Event Tracking Metadata Storage for messages processed by this Mail Class.
This can be overridden by the X-GreenArrow-EventTrackingMetadataStorage message header.
Available options:
system_default | |
local | |
stateless | |
external |
mail_class default {
event_tracking_metadata_storage external
}
mail_class * {
event_tracking_metadata_storage stateless
}
GreenArrow can (and by default, does) automatically add a List-Unsubscribe
header to SimpleMH messages
(if it is not already present). This header includes both HTTP and mailto:
List-Unsubscribe
options (unless Bounce & FBL Handling is disabled, in which case only the HTTP option will be added).
You can specify your own HTTP endpoint using the X-GreenArrow-List-Unsubscribe-HTTP-URL header.
This directive is used to explicitly enable the above behavior, or disable it.
mail_class orders {
auto_list_unsubscribe_header no
}
This directive controls how statistics are grouped for this mail class. A thorough explanation of the options and ramifications are discussed in the Statistic Report Grouping documentation.
The default of this directive is ordinarily Per Day
, but is affected by the legacy_behavior directive
default_statistic_report_grouping_per_instanceid_legacy
.
Valid options:
per_instanceid_legacy
per_instanceid
per_instanceid_and_day
per_day
per_hour
Engine Users
When this directive is turned on, Engine Users in GreenArrow’s internal database are replaced with those specified in the configuration file.
general {
define_engine_users_in_config_file yes
}
This directive is used to specify the password that is used to login to GreenArrow for message injection, API access, and admin UI access.
If you don’t want to embed the raw password in greenarrow.conf
, see the
engine_user_password_encoded configuration directive instead.
Either engine_user_password or engine_user_password_encoded must be specified on each engine_user.
Leading and trailing whitespace is trimmed from the password.
engine_user "[email protected]" {
engine_user_password "my-secret-password"
engine_user_permission all
}
This directive is used to specify the password that is used to login to GreenArrow for message injection, API access, and admin UI access.
This is an alternative to engine_user_password for cases where you don’t
want to embed the user’s password directly into greenarrow.conf
.
Although this directive is called “encoded”, that’s a bit of a misnomer (as encode kind of implies a decode is available). Passwords are 1-way hashed and cannot be retrieved based upon the “encoded” value.
You can encode a password using the greenarrow encode_mailbox_password
command. Either you can provide the password on the command line as an
additional argument, or provide the --prompt
parameter to have the password
read from the terminal. This command will print the encoded password to STDOUT.
$ greenarrow encode_mailbox_password mysecret
v1.c37f5859.519996598087b0c6798245b7c3415f83ea4bad03d4f4e46791221a486727de7d
$ greenarrow encode_mailbox_password --prompt
Enter password: <enter password first time>
Enter password (confirm): <confirm password>
v1.e882daca.e942a48c719cfca5af173827a1546f985a1408543743f7ed4bd20a7c96e19dd4
Then, take the encoded password and embed it into your configuration:
engine_user "[email protected]" {
engine_user_password_encoded "v1.c37f5859.519996598087b0c6798245b7c3415f83ea4bad03d4f4e46791221a486727de7d"
engine_user_permission all
}
Either engine_user_password or engine_user_password_encoded must be specified on each engine_user.
This directive is used to specify the 2FA shared secret that is used to login to GreenArrow for admin UI access.
Two-Factor Authentication is never required for the following:
- Message injection
- GreenArrow Engine API
- GreenArrow Studio API
To generate a new OTP shared secret, run the following command:
$ greenarrow users generate_otp_secret
LJ3IMFSROTIXHPYDCJDIHVYGYOGFRXJ7
Then, take the generated secret and embed it into your configuration:
engine_user "[email protected]" {
engine_user_password_encoded "v1.c37f5859.519996598087b0c6798245b7c3415f83ea4bad03d4f4e46791221a486727de7d"
engine_user_otp_secret LJ3IMFSROTIXHPYDCJDIHVYGYOGFRXJ7
engine_user_permission all
}
That secret can be added to your authentication app (e.g. 1Password) to generate One-Time Passwords. This user will now be required to provide a One-Time Password when signing into the configuration UI.
This directive is used to disable an Engine user from being able to access message injection, API access, and admin UI access.
This has the same effect as setting all permissions to no
.
engine_user "[email protected]" {
engine_user_password "my-secret-password"
engine_user_permission all
engine_user_disabled yes
}
This directive is used to limit what this user may access in GreenArrow Engine.
At least one of the options below must be specified.
all |
Grant all permissions to this user (this is the equivalent of |
injection |
Permission to message injection. May be set to one of: |
api |
Permission to the Engine API. May be set to one of: |
ui |
Permission to the Engine UI. May be set to one of: |
Later parameters to this directive override earlier ones (so an “all” at the end of the parameter list would supercede any other settings earlier in the permission list).
This directive must be specified on each engine_user.
engine_user "[email protected]" {
engine_user_password "my-secret-password"
engine_user_permission injection=http-only api=no ui=read-only
}
engine_user "[email protected]" {
engine_user_password "my-secret-password"
engine_user_permission all
}
An optional mail class. When this is specified, messages injected by this user will be forced to use the specified mail class (ignoring any mail class requested at the time of injection).
The specified mail class must exist in order for the configuration file to be valid.
With this configured, the X-GreenArrow-MailClass header is ignored for messages injected by this user.
engine_user "[email protected]" {
engine_user_password "my-secret-password"
engine_user_permission injection=yes api=no ui=no
engine_user_force_mail_class user_example_com
}
This directive can be used to hide particular users from the UI and API.
Users can still be edited by users with editing permission to access the UI or API, but these users will not be shown in the listing UI or API endpoints.
general {
hide_engine_user super-admin
hide_engine_user "[email protected]"
}
Performance Tuning
GreenArrow Studio
The settings in this section pertain to GreenArrow Studio.
The number of message generation processes each campaign will start.
Usage of this directive depends on how you use your system. If you tend to send a small number of large campaigns, increasing this can improve overall performance. If you tend to send a large number of campaigns, increasing this can sometimes lower overall performance.
If you want to see if this directive can increase your performance, we
recommend you observe the value automatically selected by GreenArrow using the
greenarrow_config show_dynamic_defaults
command and make small adjustments
to that value.
WARNING: This directive can significantly effect the memory utilization of Studio. Please make sure that you have enough memory for any values that you enter here. See our Memory Utilization documentation for more information.
WARNING: Increasing this directive will require more Postgres concurrent connections from the Postgres database server. Please ensure you have enough concurrent connections. If the number of Postgres database connections is being automatically set (this is the default), this may be as simple as reloading the Postgres configuration – which will cause downtime. If you have specified postgres_max_connections, see that directive for more information.
general {
studio_message_generation_processes_per_campaign 2
}
The number of “shared” workers that are created to send campaigns. If there are no campaigns to send, these workers can also perform imports, exports, and other background jobs – excluding transactional email. Using this along with zero values for studio_workers_general and studio_workers_imports means that if enough campaigns are running, all imports/exports and general tasks will have to wait until the campaigns are done – which is not desirable.
We only recommend using shared workers on very low memory systems, because it is better to have a dedicated number of workers for each type of task.
NOTE: GreenArrow may adjust the maximum number of PostgreSQL connections when this directive is used. To apply changes reload services and PostgreSQL by running greenarrow_config reload reload_postgres
. This will cause downtime and will disrupt all running services. See this section for details.
general {
studio_workers_shared 2
}
The number of workers that are created exclusively to send campaigns. This should generally be used in favor of studio_workers_shared.
Each of these workers can send a single campaign at a time, so this is the setting to adjust if you want to send more concurrent campaigns than the Dynamic Defaults allow.
NOTE: GreenArrow may adjust the maximum number of PostgreSQL connections when this directive is used. To apply changes reload services and PostgreSQL by running greenarrow_config reload reload_postgres
. This will cause downtime and will disrupt all running services. See this section for details.
general {
studio_workers_campaigns 2
}
The number of workers that are created to run other background jobs. These workers handle most background activity in GreenArrow Studio. The things that are not handled by these workers include imports, exports, transactional email, and campaigns.
Examples of general tasks include recording a click to the database and calculating the estimated number of recipients in a campaign.
NOTE: GreenArrow may adjust the maximum number of PostgreSQL connections when this directive is used. To apply changes reload services and PostgreSQL by running greenarrow_config reload reload_postgres
. This will cause downtime and will disrupt all running services. See this section for details.
general {
studio_workers_general 2
}
The number of workers that are created to handle imports and exports.
NOTE: GreenArrow may adjust the maximum number of PostgreSQL connections when this directive is used. To apply changes reload services and PostgreSQL by running greenarrow_config reload reload_postgres
. This will cause downtime and will disrupt all running services. See this section for details.
general {
studio_workers_imports 2
}
The number of workers that are created to deliver transactional email - this includes autoresponders, campaign previews, web form confirmation, and any other non-campaign emails sent from GreenArrow Studio.
NOTE: GreenArrow may adjust the maximum number of PostgreSQL connections when this directive is used. To apply changes reload services and PostgreSQL by running greenarrow_config reload reload_postgres
. This will cause downtime and will disrupt all running services. See this section for details.
general {
studio_workers_transactional 2
}
HTTP Server
The settings in this section are related to the Apache HTTP Server and the Passenger application server.
This sets the PassengerMaxRequestQueueSize directive in Passenger, the maximum number of requests that can sit in Passenger’s queue waiting for an application instance.
To apply changes to this directive, run greenarrow_config reload_passenger
.
general {
passenger_max_requests_in_queue 2
}
This sets the PassengerMinInstances directive in Passenger, the minimum number of instances of the application server which handles HTTP/HTTPS requests that should be kept running at any time.
To apply changes to this directive, run greenarrow_config reload_passenger
.
general {
passenger_min_application_instances 2
}
This sets the PassengerMaxPoolSize directive in Passenger, the maximum number of instances of the application server which handles HTTP/HTTPS requests that should be kept running at any time. On servers that are not low on memory, we recommend keeping the minimum and maximum equal.
To apply changes to this directive, run greenarrow_config reload_passenger
.
general {
passenger_max_application_instances 2
}
This sets the MaxClients and ServerLimit directives in Apache. These limit the number of HTTP/HTTPS sessions that Apache can handle simultaneously.
general {
apache_max_clients 2
}
Bounce Processor
Ordinarily, when the bounce processor cannot process message received to a bounce
mailbox, a copy of that message is written to
/var/hvmail/maildata/Maildir-bounce/.INBOX.CouldNotProcess/new
. When
write_could_not_process_bounce_messages
is turned off, these messages will not
be written.
The most common usage of this option comes in tandem with Obscured Email Addresses, to reduce the amount of recipient data written to disk by GreenArrow.
general {
write_could_not_process_bounce_messages no
}
This directive is used for adding one or more custom bounce processor rules. This is useful if you find a particular bounce message is misclassified by GreenArrow.
The bounce code must be between 0 and 199 (inclusive).
The regular expression can be specified in any of the supported string formats, including double-quotes, backticks, or regular expression forward slashes. See the String Encoding and Regular Expression Encoding sections above for more information.
The regular expression syntax used is that understood by the Go programming language.
For GreenArrow’s reporting to show the bounce codes in its reporting, we encourage you to only use bounce processor codes understood by GreenArrow. See this page for a list of bounce codes.
The text that the regular expression matches against is the contents of
the bounce_text
that is included in the bounce_all
event,
with the pre_lowercase
and normalize_whitespace
transformations applied, if
configured for the bounce rule.
If you’d like to write regular expressions based on the delivery_attempt.message
field,
please note that the following transformations occur on that field that don’t occur
on the bounce_all.bounce_text
field:
- More bytes are replaced with
_
, and - all newlines are replaced with
/
instead of only some of them.
As such, we recommend the following when writing such regular expressions based on the
delivery_attempt
event:
- Replace
_
with.
, and - replace
/
with[\n/]+
.
Optional arguments:
case_insensitive
boolean /default: |
Match the regular expression case insensitively. |
pre_lowercase
boolean /default: |
Lowercase the bounce text prior to matching the regular expression. This offers a slight performance improvement when many bounce_processor_rule directives are used. When using this, your regular expression should be written all-lowercase. |
normalize_whitespace
boolean /default: |
Condense all consecutive whitespace (spaces, tabs, newlines, and carriage returns) in the bounce text into single spaces. This can make it easier to write matchers. |
general {
bounce_processor_rule /user \S+ does not exist/ 10
bounce_processor_rule /that is spam/ 52 case_insensitive=yes
}
After GreenArrow makes a delivery attempt that communicates with a remote SMTP server, the SMTP response will be evaluated for a bounce code.
This configuration directive is provided to disable this behavior.
general {
delivery_attempt_bounce_categorization no
}
When delivery of a message fails within GreenArrow, ordinarily a bounce message is created
to notify the sender (the MAIL FROM
/ RFC5321.MailFrom address) that the message could not be
delivered. This directive disables that behavior, preventing the bounce message
from being generated.
This option has the effect of preventing bounce_all
and bounce_bad_address
events from being created as a result of synchronous bounces, as those events
are generated based upon the processing of these bounce messages.
general {
create_bounce_messages no
}
Database Server
The maximum number of concurrent connections allowed to be made to the PostgreSQL database server.
To apply changes to this directive, run greenarrow_config reload_postgres
.
general {
postgres_max_connections 200
}
By default, the following equation is used, rounded up to the next 100:
100 +
(6 + studio_message_generation_processes_per_campaign) *
(studio_workers_shared + studio_workers_campaigns) +
2 * (studio_workers_general + studio_workers_imports + studio_workers_transactional) +
passenger_max_application_instances +
apache_max_clients +
simplemh_max_servers +
2 + 3*count(event_delivery_destinations) +
bounce_processor_concurrency (/var/hvmail/control/bounce.concurrency) +
event_processor_concurrency (/var/hvmail/control/event_processor.json) +
simplemh2_workers (/var/hvmail/control/opt.simplemh.redis_num_workers)
In the above equation, entries that are not configuration directives documented on this page are noted with what file is used to edit that value.
System Resources
The system resources directives are normally only used to decrease GreenArrow’s view of what resources are available. For example, it could make sense to do that if you’re running non-GreenArrow applications on the same server.
This directive overrides GreenArrow’s view of how much RAM exists in this system. This causes dynamic defaults to be set based upon this amount of RAM, instead of the actual amount of RAM.
This does not cause GreenArrow to use more or less RAM, except as an effect of changed dynamic defaults.
general {
system_memory_gigabytes 8.5
}
This directive overrides GreenArrow’s view of how many CPU cores exist in this system. This causes dynamic defaults to be set based upon this number of CPU cores, instead of the actual number of CPU cores.
This does not cause GreenArrow to use more or less CPU, except as an effect of changed dynamic defaults.
general {
system_cpu_core_count 4
}
SimpleMH
The maximum number of messages that SimpleMH can process concurrently.
This directive only applies to SimpleMH email injected via SMTP (not the HTTP Submission API), is rarely needed, and in general should only be adjusted upon consultation from GreenArrow.
To apply changes to this directive, run greenarrow_config reload_simplemh
.
general {
simplemh_max_servers 20
}
The minimum number of processes that SimpleMH will keep running.
This directive only applies to SimpleMH email injected via SMTP (not the HTTP Submission API), is rarely needed, and in general should only be adjusted upon consultation from GreenArrow.
To apply changes to this directive, run greenarrow_config reload_simplemh
.
general {
simplemh_min_servers 20
}
The maximum number of idle processes that SimpleMH will keep running. If more processes than this value are idle, they’ll be stopped until needed again.
This directive only applies to SimpleMH email injected via SMTP (not the HTTP Submission API), is rarely needed, and in general should only be adjusted upon consultation from GreenArrow.
To apply changes to this directive, run greenarrow_config reload_simplemh
.
general {
simplemh_max_spare_servers 20
}
The minimum number of idle processes that SimpleMH will keep running. If fewer processes than this are idle, more will be started (up to a maximum of simplemh_max_servers).
This directive only applies to SimpleMH email injected via SMTP (not the HTTP Submission API), is rarely needed, and in general should only be adjusted upon consultation from GreenArrow.
To apply changes to this directive, run greenarrow_config reload_simplemh
.
general {
simplemh_min_spare_servers 20
}
The maximum number of messages that a single SimpleMH process will handle before exiting.
This directive only applies to SimpleMH email injected via SMTP (not the HTTP Submission API), is rarely needed, and in general should only be adjusted upon consultation from GreenArrow.
To apply changes to this directive, run greenarrow_config reload_simplemh
.
general {
simplemh_min_spare_servers 500
}
The maximum service life of a single SimpleMH process. After this time, it will be closed. If needed for current load, a new process will be started in its place.
Some randomization will be added to this value – a random value from 90% to 110% of the configured setting will be used. This prevents processes from expiring simultaneously, creating a “thundering herd” effect.
It’s rare for this directive to need to be tuned.
To apply changes to this directive, run greenarrow_config reload_simplemh
.
general {
simplemh_max_server_lifetime_seconds 30
}
GreenArrow’s API and interface will ordinarily validate that bounce addresses configured on SimpleMH mail classes are either bounce mailboxes configured on an incoming email domain, or that it is configured as a bounce_address_external.
Setting this directive to no
will disable that validation and present the bounce address
configuration as a text field instead of a dropdown.
general {
simplemh_validate_bounce_address no
}
GreenArrow’s HTTP Submission API stores incoming messages in memory until SimpleMH can process them. This directive limits the number of messages that can be in memory waiting for SimpleMH processing. When this limit is met, the HTTP API slows down how fast it accepts messages.
Setting this value too low can result in throttling on HTTP injection.
The maximum value for this directive is 10000
. Setting this value too high can result in
excessive CPU being used on systems that are already in a state of back-pressure.
general {
simplemh_processing_queue_max_messages 100
}
GreenArrow’s HTTP Submission API stores incoming messages in memory until SimpleMH can process them. This directive limits the total size of message data that can be in memory waiting for SimpleMH processing. When this limit is met, the HTTP API slows down how fast it accepts messages.
Setting this value too low can result in throttling on HTTP injection.
The default for the directive is calculated by starting with 2% of system memory, and if this value is smaller than 100mb, then 100mb is used as the default, and if it is greater than 1gb, then 1gb is used as the default.
Set to 0 to disable this limit (not recommended).
general {
simplemh_processing_queue_max_memory 200mb
}
The number of processes dedicated to working on messages injected via the HTTP Submission API.
The default for this value is set based on the number of CPU cores and system memory:
MAX(5, MIN(NUM_CPU * 2, NUM_RAM_GB * 2))
This default is satisfactory for most installations.
To apply changes to this directive, run greenarrow_config reload_simplemh
.
general {
simplemh_http_workers 20
}
Enabling this directive will use compression to shrink the size of click and open tracking links generated by SimpleMH.
This is most useful in combination with Event Tracking Metadata Storage.
This directive does not apply to messages that use External Metadata Event Tracking.
general {
simplemh_compress_links yes
}
GreenArrow contains legacy code that interacts with its more modern Go code. This directive tunes Go’s garbage collector when interacting with that legacy code.
Increasing this value can effect lower CPU usage, at the expense of higher memory usage.
general {
hvmailgo_gc 800
}
GreenArrow contains legacy code that interacts with its more modern Go code. This directive sets a soft limit on how much memory the Go process can use before the garbage collector kicks in.
This directive should typically be set in coordination with GreenArrow Technical Support.
general {
hvmailgo_memory_limit 8mb
}
Enabling this directive will cause GreenArrow to read (and optionally remove) the X-Job
header
from authenticated incoming email (excluding raw injection email).
If both the X-Job
header and X-GreenArrow-InstanceID
header
are provided, the value in the X-Job
header will take precedence and be used.
This option exists to make migrating to GreenArrow from other vendors easier, to reduce the changes required to your email injectors.
If this directive is enabled and remove
is not specified, the X-Job
header will be removed by default.
general {
process_x_job_header yes remove=yes
}
Enable or disable Bad Address Suppression.
general {
simplemh_bad_address_remove yes
}
The domain SimpleMH uses when rewriting the email address in Bad Address Suppression. The default value is a special domain that will accept and discard all emails, so this should not be modified without careful consideration.
general {
simplemh_bad_address_dev_null_domain badaddress.discardallmail.drh.net
}
The prefix used with GreenArrow Monitor. This value is set for you when you purchase a Monitor subscription so it should not be modified unless you’re instructed to do so by GreenArrow Technical Support.
general {
simplemh_greenarrow_monitor_prefix fsasyadrh
}
The Mail Class to use when a message gets injected using SimpleMH, but without specifying a Mail Class.
The default for this directive is the mailclass name default
. If no such mail class exists,
then direct injection will be used, and the message will not be processed by SimpleMH.
This directive may be set to __NONE__
to force these messages to use direct
injection and not be processed by SimpleMH.
general {
simplemh_default_mailclass default
}
The email address used when overwriting the original Sender:
header address for
messages processed by SimpleMH.
general {
simplemh_sender_header_override [email protected]
}
This directive defines a regular expression which, when the From
header matches,
will prevent the simplemh_sender_header_override from taking effect.
The regular expression, in addition to meeting the requirements defined above in this document, must be a valid PCRE regular expression.
general {
simplemh_sender_header_override [email protected]
simplemh_sender_header_override_exempt /(?i)@example.com$/
}
Event Processor
By default, GreenArrow will periodically perform a “shrink” of the events
table. This is to reduce its disk usage and improve its performance. This
directive is used to disable this behavior. When enabled, the command
greenarrow shrink_events_table
can still be used to perform this operation
(it just won’t happen automatically).
general {
disable_automatic_shrink_events_table yes
}
Disk Queue Message Writing
All messages receive an initial delivery attempt from GreenArrow’s RAM queue. If the message is successfully delivered, it never needs to exist “on disk” – leading to very high performance. However, if the message is deferred and needs to be retried, it will be written to a disk queue.
The following configuration directives tune how and when messages are written to the disk queue.
The number of messages that are batched together into a single “message batch” file. A larger message batch configuration can lead to improved performance, reducing the amount of disk activity needed to deliver messages – at the cost of disk space (since the message batch won’t be deleted until all messages in the batch have either succeeded or failed). A smaller message batch configuration conserves disk space, by allowing message batches to be deleted sooner after the messages within the batch have succeeded or failed.
Most installations should use the default batch size of 10
.
general {
disk_queue_writer_batch_max_messages 20
}
The duration of time that GreenArrow will wait for additional messages to need to be moved to the disk queue before “closing” the open message batch. If no more messages are available by the end of this duration, the message batch will be written to the disk queue partially-filled.
Most installations should use the default value of 10s
.
general {
disk_queue_writer_batch_max_time 2s
}
The number of processes running to move messages to the disk queue.
Most installations should use the default value of 20
.
general {
disk_queue_writer_concurrency 10
}
This directive controls whether or not GreenArrow should call fsync
after
writing messages to the disk queue. This improves performance but increases the
risk that if there is a crash it will cause message(s) to get lost or
corrupted.
Most installations should use the default value of yes
.
general {
disk_queue_writer_fsync no
}
SMTP Delivery
The settings in this section control how GreenArrow delivers email via SMTP.
DNS
The maximum number of concurrent DNS queries that may be executed. It’s extremely uncommon that this value should be changed. Set this to 0 to have no limit.
general {
max_dns_queries 100
}
Automatic Back-off
Whenever a throttle program begins or ends automatic back-off, these email addresses will receive a notification.
general {
notify_on_backoff "[email protected]", "[email protected]"
}
Notification emails are sent from root@SERVER
, where SERVER
is GreenArrow’s Server Name.
The email message when backoff mode begins looks like:
Subject: Dynamic Delivery: 127.0.0.101; first.example.com, ...; Backoff mode started
Backoff mode started
Backoff mode will last until 2018-03-21 12:39:07 CDT.
This throttle:
https://example.com/ga/eui/virtual_mta/eng_throttles/45
IP Address:
127.0.0.101
ip-1.example.com
https://example.com/ga/eui/virtual_mta/ip_addresses/74
Domains:
first.example.com
second.example.com
example.com
Logged information:
backoff mode began
failure rate (60/120; 50.00%) exceeds limit of 20%
combined failure and deferral rate (60/120 failures; 0/120 deferrals; 50.00%) exceeds deferral limit of 30%
The email message when backoff mode ends looks like:
Subject: Dynamic Delivery: 127.0.0.101; first.example.com, ...; Backoff mode ended
Backoff mode ended
This throttle:
https://example.com/ga/eui/virtual_mta/eng_throttles/45
IP Address:
127.0.0.101
ip-1.example.com
https://example.com/ga/eui/virtual_mta/ip_addresses/74
Domains:
first.example.com
second.example.com
example.com
Logged information:
backoff mode ended
This directive allows you to specify that SMTP backoff mode should begin when an SMTP response message matches the specified regular expression.
This has no effect unless there is an explicit throttle rule defined for the domain (i.e. it does not work for domains caught by the “Default Throttling Rule”).
smtp_match_begin_backoff_mode is not evaluated if an smtp_pattern matched and
that pattern included the backoff=
option.
For multiple smtp_match_begin_backoff_mode directives, evaluation will be done in order of tighter precedence to broader precedence (as defined in the domain directive). Directives at the same level of precedence will be evaluated in the order they are defined in the configuration file. The first directive to match in this order of evaluation will be used.
If a throttle is already in SMTP backoff mode, this directive will not override the active backoff mode.
Optional arguments:
smtp_result
string |
Only backoff if the original SMTP result was this (either |
||||||||
case_insensitive
boolean /default: |
Match the regular expression case insensitively. |
||||||||
pre_lowercase
boolean /default: |
Lowercase the SMTP result text prior to matching the regular expression. This offers a slight performance improvement when many smtp_match_begin_backoff_mode directives are used. When using this, your regular expression should be written all-lowercase. |
||||||||
match_format
string /default: Match on the specified response format. Valid formats are listed below. See this page for a discussion on the differences between these formats.
|
|||||||||
default_duration
duration /default: |
The default time duration to run in backoff mode if no Throttle Program is configured for this throttle. |
||||||||
duration
duration |
The time to run in backoff mode, regardless of if a Throttle Program is
configured for this throttle. If this value is specified, it will take precedence over |
||||||||
maxconn
integer |
The maximum number of connections to establish while in backoff mode. If this value is specified, it will take precedence over any configured throttle program. |
||||||||
msgperhour
integer |
The maximum number of delivery attempts to try per hour while in backoff mode. If this value is specified, it will take precedence over any configured throttle program. |
ip_address * {
domain * {
smtp_match_begin_backoff_mode /over quota/ case_insensitive=yes
}
}
This directive limits the maximum number of concurrent outgoing connections while in Backoff Mode due to an SMTP match (smtp_pattern or smtp_match_begin_backoff_mode).
This directive only applies if the smtp_pattern or smtp_match_begin_backoff_mode does not otherwise specify the maximum number of concurrent outgoing connections.
ip_address * {
domain greenarrowemail.com {
backoff_max_concurrent_connections 1
}
}
This directive limits the maximum number of delivery attempts per hour while in Backoff Mode due to an SMTP match (smtp_pattern or smtp_match_begin_backoff_mode).
This directive only applies if the smtp_pattern or smtp_match_begin_backoff_mode does not otherwise specify the maximum delivery attempts per hour.
ip_address * {
domain greenarrowemail.com {
backoff_max_messages_per_hour 1
}
}
This directive sets how long to engage Backoff Mode following an SMTP match (smtp_pattern or smtp_match_begin_backoff_mode).
This directive only applies if the smtp_pattern or smtp_match_begin_backoff_mode does not otherwise specify the duration to remain in Backoff Mode.
ip_address * {
domain greenarrowemail.com {
backoff_return_after 20m
}
}
Outgoing Connections
The maximum number of concurrent SMTP connections that may be established. Set this to 0 to have no limit.
general {
system_max_smtp_connections 10000
}
By default, when sending emails, GreenArrow Engine attempts to deliver one message per SMTP session. This means that if an email provider imposes a limit on how many messages they accept per SMTP session, you don’t need to worry about exceeding that limitation.
For high volume email recipients, you can choose to enable connection reuse to send multiple messages in a single SMTP session. This can offer a significant performance boost when applied to your most common recipient domains.
With this setting enabled, connections are used so long as the previous delivery attempt succeeded. When a delivery attempt ends in any kind of non-acceptance (deferral, failure, or connection error), the connection is closed.
See reuse_connections_timeout and reuse_connections_max_messages to adjust for how long connections are reused.
# Reuse connections to Google on all IP addresses.
ip_address * {
domain gmail.com, googlemail.com {
reuse_connections yes
}
}
The duration for which the connection should be held open without any delivery attempts.
This value is ignored unless reuse_connections is set to yes
.
# Reuse connections on "ip-addr-3" to all domains, allowing the connection to
# idle for up to 2 seconds between deliveries.
ip_address ip-addr-3 {
domain * {
reuse_connections yes
reuse_connections_timeout 2s
}
}
The maximum number of deliveries that should to attempt on a single open connection before closing.
This value is ignored unless reuse_connections is set to yes
.
# Reuse connections on all IPs to all Domains, with a maximum of 500 messages
# per connection.
ip_address * {
domain * {
reuse_connections yes
reuse_connections_max_messages 500
}
}
This directive specifies the length of time that deferred and throttled messages should remain in the GreenArrow queue. See the Queue Lifetime documentation for more information on how this setting is used.
ip_address * {
domain example.com {
queue_lifetime 1h
}
}
By default, GreenArrow uses a dynamic retry schedule. When this directive is specified, a fixed length of time will be used between delivery attempts.
If a retry_time is specified within both an ip_address and a virtual_mta_injected, the virtual_mta_injected match will take precedence.
The minimum value for this directive is 5 seconds. In most cases, GreenArrow does not recommend a value below 10 minutes.
If multiple values are specified, each subsequent delivery attempt will receive
the next retry time. The final retry time will be used for all remaining
delivery attempts. Thus a value of retry_time 10m, 10m, 30m, 30m, 2h
will
use 10 minutes for the 2nd and 3rd delivery attempts, 30m for the 4th and 5th,
and 2h for all remaining delivery attempts.
# Mail (excluding mail matched by the configuration block below) that's
# delivered via the IP smtp-1 will have a 15 minute retry time.
ip_address smtp-1 {
domain example.com {
retry_time 15m
}
}
# All mail injected through rr-1, including mail to example.com, will have a 10
# minute retry time.
virtual_mta_injected rr-1 {
domain * {
retry_time 10m, 10m, 30m, 30m, 2h
}
}
When using a custom retry schedule (i.e. when you specify the retry_time directive), this directive may be added to cause some randomization to be added. This is only available with custom retry schedules, as GreenArrow’s built-in retry schedule already includes randomization.
This directive is useful to avoid a situation where retries happen in lock-step with each other, sometimes leading to excessive throttling deferrals.
When calculating the next retry time, GreenArrow consults the retry_time directive to determine the next retry time. If retry_time_randomize is specified, a time will be selected within ± (plus or minus) this percentage of retry_time.
This means that given a retry_time of 15m and retry_time_randomize of 20%, the next delivery attempt may occur anywhere between 12m and 18m.
ip_address smtp-1 {
domain example.com {
retry_time 10m, 10m, 30m, 30m, 2h
retry_time_randomize 50%
}
}
This directive instructs GreenArrow to attempt extra delivery attempts between
the regularly scheduled delivery attempts when a delivery attempt is deferred due
to connmaxout
(i.e. the delivery attempt is throttled).
If an extra delivery attempt is deferred, but does not receive connmaxout
(i.e. it made it through the throttle), then that extra delivery attempt will be
considered the actual delivery attempt for the sake of scheduling the next
delivery attempt.
This behavior can be disabled by setting 0 in the global throttling rule:
ip_address * {
domain * {
extra_delivery_attempts_after_conmmaxout 0
}
}
The default value for this directive is 1
if the retry_time directive
is in use. When using the built-in retry schedule
the default value for this directive is 0
.
ip_address smtp-1 {
domain example.com {
retry_time 10m, 10m, 30m, 30m, 2h
extra_delivery_attempts_after_conmmaxout 5
}
}
This directive instructs GreenArrow how to handle messages to recipient email
domains with no MX
records. The default behavior (i.e. when this directive is
either not specified or disabled) in this case is to try the A
record.
This directive lets you effect one of the following behaviors:
- By enabling this directive and not specifying
after=
, these delivery attempts will end in failure and bounce the message. - By enabling this directive and specifying
after=
, these delivery attempts will try theA
record until such time as the message is older than the time specified byafter=
. In this case, all such messages (regardless of the value ofafter=
) will receive at least a single initial delivery attempt.
This directive will also affect delivery directly to IP addresses (for example,
delivering to [email protected]
). In such a case, the delivery attempt will be
treated as though no MX record exists.
Messages that bounce due to this directive will have a
Remote Delivery Attempt Error Message
of Sorry, the host named \{HOSTNAME\} does not have any MX records, and delivery without MX records prohibited by local policy. (#5.1.0)
and receive a bounce_code
of 24
(Temp failure - Missing MX record
).
# In this case, recipient email domains will not receive any delivery attempts
# if they do not have an MX record.
ip_address smtp-1 {
domain * {
bounce_recipients_with_no_mx yes
}
}
# In this case, recipient email domains with no MX record will have their A record
# attempted for 30 minutes. After that time, the message will bounce.
ip_address smtp-2 {
domain * {
bounce_recipients_with_no_mx yes after=30m
}
}
Encryption
When this directive is enabled for a domain (including the *
wildcard domain),
GreenArrow issues the STARTTLS
command to servers that offer it.
If the server replies to STARTTLS
with an error, the existing connection is used
without TLS - unless starttls_require is enabled.
# Override the default to always try to use STARTTLS if it's available.
ip_address * {
domain * {
starttls_use yes
}
}
# However - on this IP, we don't want to use STARTTLS to Gmail.
ip_address smtp-7 {
domain gmail.com, googlemail.com {
starttls_use no
}
}
When this directive and starttls_use are both enabled, email is not delivered unless a STARTTLS connection can be established:
-
If the remote server does not offer the STARTTLS command, the type of response is determined by the starttls_require_action directive.
-
If an error occurs while establishing a STARTTLS connection, a temporary failure is returned. This differs from GreenArrow’s standard behavior, which would result in the message being delivered without TLS.
# Override the default to always try to use STARTTLS if it's available.
ip_address * {
domain * {
starttls_use yes
}
# Don't deliver to Google unless we're in TLS.
domain gmail.com, googlemail.com {
starttls_require yes
}
}
When starttls_require is enabled, this directive determines
what to do if STARTTLS
is unavailable or unsuccessful.
perm_failure |
A permanent failure is returned and the message is not retried. The following message is returned:
|
temp_failure |
A temporary failure is returned and the message may be retried. The following message is returned:
|
discard |
A fake “success” is generated to prevent the message from being retried. The following message is returned:
|
# Override the default to always try to use STARTTLS if it's available.
ip_address * {
domain * {
starttls_use yes
}
}
# Discard email for Yahoo that can't be sent with TLS.
ip_address * {
domain yahoo.com {
starttls_require yes
starttls_require_action discard
}
}
Overrides
Pause deliveries to this IP address. The effect is similar to pausing individual sends in Engine’s user interface, but applies to an entire IP address.
While an IP is paused, all delivery attempts will defer with the message
Delivery paused.
.
If an IP address is both paused and redirected, the pause will take priority and delivery attempts will be paused.
This directive cannot be applied to the wildcard (*
) IP address and is
only effective when define_virtual_mtas_in_config_file is turned on.
ip_address smtp-1 {
delivery_paused yes
}
Override delivery attempts.
The first argument (mode
) is required and accepts the following options:
none
, perm_failure
, temp_failure
, or discard
.
If the second argument (message
) is supplied, it will be used as the message
in the delivery attempt log. If not supplied, a default message will be
generated as follows.
none |
No delivery override occurs. |
perm_failure |
No delivery attempt occurs; instead, a fake permanent failure is returned:
|
temp_failure |
No delivery attempt occurs; instead, a fake temporary failure (deferral) is returned:
|
discard |
No delivery attempt occurs; instead, a fake acceptance is returned:
|
# Discard all email for yahoo.com and gmail.com. Do not attempt delivery.
ip_address * {
domain yahoo.com {
delivery_override discard
}
domain gmail.com {
delivery_override discard "Not delivering to Gmail"
}
}
Override the destination to which email is delivered. The argument may include a port number following a colon. If the port number is not specified, port 25 is assumed.
Formerly, this was accomplished using the /var/hvmail/control/smtproutes
file. If that file exists, it is used at a lower precedence than this
smtp_route directive.
ip_address * {
# Deliver all Yahoo mail to localhost port 2500.
domain yahoo.com {
smtp_route 127.0.0.1:2500
}
# Deliver all Microsoft mail to Google??? That's weird...
domain msn.com, hotmail.com {
smtp_route smtp.googlemail.com:25
}
}
Redirect mail for specific domains in an IP address to another VirtualMTA.
This directive may not be specified in the *
or **super**
wildcard ip_address.
This directive may be specified in the *
wildcard domain, but be aware that this
will effectively prevent all deliveries from going out of that IP address. This is regardless
of if there exists domain blocks that do not specify redirect_to_virtual_mta
(because those blocks will inherit redirect_to_virtual_mta from the domain *
block).
ip_address ipaddr-1 {
# We want all Yahoo mail to go through the yahoo-mail routing rule.
domain mx:[*.]yahoodns.net {
redirect_to_virtual_mta yahoo-mail
}
}
This directive allows you to override the SMTP result (either success
,
perm_failure
, temp_failure
, or no_override
) based upon a regular expression matching the
SMTP response.
The options success
, perm_failure
, or temp_failure
will end the delivery attempt.
The option no_override
uses whatever the original SMTP result was. This is provided so that
you can, for example, specify skip_mx
to this directive without overriding the SMTP result.
override_smtp_result is not evaluated if an smtp_pattern matched and
that pattern included the result=
option.
This directive will not override a success
result to a temp_failure
result, so that it will not cause a duplicate delivery of an email.
Optional arguments:
smtp_result
string |
Only override if the original SMTP result was this (either |
||||||||
case_insensitive
boolean /default: |
Match the regular expression case insensitively. |
||||||||
pre_lowercase
boolean /default: |
Lowercase the SMTP result text prior to matching the regular expression. This offers a slight performance improvement when many override_smtp_result directives are used. When using this, your regular expression should be written all-lowercase. |
||||||||
match_format
string /default: Match on the specified response format. Valid formats are listed below. See this page for a discussion on the differences between these formats.
|
|||||||||
skip_mx
boolean |
If the SMTP result is not |
ip_address * {
domain * {
override_smtp_result /over quota/ success case_insensitive=yes
}
}
Error Handling
Define what the delivery result should be when the delivery attempt has a
connection failure (at either the TCP or TLS layer) or a timeout while the
message is transferring. This directive applies until the .
is sent, at
which point the message_transfer_response_timeout_action directive applies.
perm_failure |
A permanent failure is returned and the message is not retried. The following message is returned:
|
temp_failure |
A temporary failure is returned and the message may be retried. The following message is returned:
|
discard |
A fake “success” is generated to prevent the message from being retried. The following message is returned:
|
ip_address * {
# Message transfer timeouts shouldn't be retried.
domain yahoo.com {
message_transfer_timeout_action perm_failure
}
}
Define what the delivery result should be when the delivery attempt has a
connection failure (at either the TCP or TLS layer) or a timeout after the .
is sent.
This is the critical period where a timeout or disconnection can cause a duplicate message delivery.
perm_failure |
A permanent failure is returned and the message is not retried. The following message is returned:
|
temp_failure |
A temporary failure is returned and the message may be retried. The following message is returned:
|
discard |
A fake “success” is generated to prevent the message from being retried. The following message is returned:
|
ip_address * {
domain * {
message_transfer_response_timeout_action discard
}
}
DKIM
The pcompat_dkim_*
directives described in this section only work with SimpleMH. They’re ignored for all other types of email.
selector |
The selector to use in the DKIM signature. |
domain_name |
Domain name of the key. |
private_key_filename |
A filename containing a private key in PEM format (must be an absolute path). |
This directive is to provide compatibility with the PowerMTA configuration
directive domain-key
to aid in migrating from PowerMTA to GreenArrow.
This specifies DKIM private keys used by the PowerMTA compatibility DKIM signing system. DKIM keys specified with this directive are not available to use by the X-GreenArrow-DKIM header.
This directive can be specified multiple times to provide multiple DKIM keys that could apply.
What domain name may be used in the signature depends on the pcompat_dkim_identity:
If there IS NOT a pcompat_dkim_identity value defined (or it is set to
sender-or-from
), then a DKIM key matching one of these domain names is
searched for. The first match is used:
- The domain name specified in the RFC5322.Sender (
Sender
header), if present - The domain name specified in the RFC5322.From (
From
header)
If there IS a pcompat_dkim_identity value defined, then a DKIM key matching this domain name is searched for:
- The domain name specified in pcompat_dkim_identity
- If found, then the pcompat_dkim_identity domain name is used
as the
i=
parameter in the signature, and the domain name in the matched pcompat_dkim_key record is used as thed=
parameter (except for a*
domain, where the pcompat_dkim_identity domain name is used as thed=
parameter)
- If found, then the pcompat_dkim_identity domain name is used
as the
Searching for a DKIM key that matches a domain name is done as follows:
-
Keys defined in an exact-match virtual_mta_injected are searched before keys in a wildcard-matching (
*
) virtual_mta_injected block. -
Inside of a matching virtual_mta_injected block, the first key (in the order specified in the configuration file) that contains a domain name matching one of these criteria:
- Equal to the “search domain name”
- A parent domain name of the “search domain name” – the domain name specified with DKIM key is used in the DKIM signature
- A domain of
*
– the “search domain name” is used in the DKIM signature
Note: because domain names are matched in the order specified in
the configuration file, any pcompat_dkim_key record with a domain
name of *
should be the last pcompat_dkim_key record in the
containing virtual_mta_injected block.
If none of the above matched a configured pcompat_dkim_key, the
pcompat_dkim_identity_fallback directive is checked. If a key is
found for the fallback domain, DKIM signing wil proceed. Otherwise, no
DKIM signing is performed as a result of the pcompat_*
directives.
# This DKIM key will be available to signing done within the "virtual_mta_injected" block,
# this DKIM signing is performed at the time of injection.
virtual_mta_injected ipaddr-1 {
pcompat_dkim_key selector example.com /path/to/private_key_filename.pem
}
#
# This DKIM key will be available to signing done within the "ip_address" block,
# this DKIM signing is performed during delivery.
ip_address ipaddr-1 {
pcompat_dkim_key selector example.com /path/to/private_key_filename.pem
}
This is to provide compatibility with the PowerMTA configuration directive
dkim-sign
to aid in migrating from PowerMTA to GreenArrow.
If enabled, the PowerMTA compatibility DKIM signing system will add a DKIM signature to messages at the time of injection - if a matching DKIM key is found as described in pcompat_dkim_key.
When defined within the virtual_mta_injected context, DKIM signing will be performed at the time of injection. When defined within the ip_address context, DKIM signing will be performed during delivery.
virtual_mta_injected * {
pcompat_dkim_sign yes
}
ip_address ipaddr-1 {
domain [*.]destination.com {
pcompat_dkim_sign yes
}
}
This is to provide compatibility with the PowerMTA configuration directive
dkim-identity
to aid in migrating from PowerMTA to GreenArrow.
This is used to DKIM sign an email with a domain name that is not in the Sender or From header.
This may be set to sender-or-from
in order to sign using the Sender or From domain.
For a description of how this is used, see the documentation of the pcompat_dkim_key directive.
virtual_mta_injected * {
pcompat_dkim_sign yes
pcompat_dkim_identity example.com
}
ip_address ipaddr-1 {
domain [*.]example.com {
pcompat_dkim_sign yes
pcompat_dkim_identity example.com
}
}
This is to provide compatibility with the PowerMTA configuration directive
dkim-identity-fallback
to aid in migrating from PowerMTA to GreenArrow.
This directive is used to provide a fallback signing identity when the primary DKIM identity (as declared by either using the pcompat_dkim_identity directive or the Sender or From domain) has no configured DKIM keys using the pcompat_dkim_key directive.
For a description of how this is used, see the documentation of the pcompat_dkim_key directive.
virtual_mta_injected * {
pcompat_dkim_identity_fallback example.com
}
ip_address ipaddr-1 {
domain * {
pcompat_dkim_sign yes
pcompat_dkim_identity_fallback example.com
}
}
This directive provides the same functionality as pcompat_dkim_sign, but for a second DKIM signature. The presence of the “first” DKIM signature does not affect whether or not the “second” DKIM signature is added.
ip_address ipaddr-1 {
domain * {
pcompat_second_dkim_sign yes
}
}
This directive provides the same functionality as pcompat_dkim_identity, but for a second DKIM signature. The presence of the “first” DKIM signature does not affect whether or not the “second” DKIM signature is added.
ip_address ipaddr-1 {
domain * {
pcompat_second_dkim_sign yes
pcompat_second_dkim_identity example.com
}
}
This directive provides the same functionality as pcompat_second_dkim_identity_fallback, but for a second DKIM signature. The presence of the “first” DKIM signature does not affect whether or not the “second” DKIM signature is added.
ip_address ipaddr-1 {
domain * {
pcompat_second_dkim_sign yes
pcompat_second_dkim_identity_fallback example.com
}
}
This grouping context creates a DKIM key list. These key lists are referenced by
the X-DKIM-Options
header when support for that header is enabled by the
pcompat_process_x_dkim_options_header configuration directive.
pcompat_dkim_key_list key-list-1 {
pcompat_dkim_key sel domain.com /root/domain.pem
pcompat_dkim_key sel domain2.com /root/domain2.pem
}
This directive enables processing of the X-DKIM-Options
header. When the
remove
option is set, the X-DKIM-Options
header will also be removed from
the message.
If this directive is enabled and remove
is not specified, the X-DKIM-Options
header
will be removed from the message. To disable this behavior, set remove=no
.
The format of the X-DKIM-Options
header is similar to the DKIM-Signature
header. It consists of pairs of setting=value
fields connected with semicolons
(;
). Whitespace may be added before or after the semicolons.
s |
Require the DKIM key selected to match this selector. This specifies the |
d |
Require the DKIM key selected to match this domain. This specifies the |
i |
Specify the |
q |
Query method: this attribute specifies the value for the |
key-list |
Specify the pcompat_dkim_key_list from which to select the DKIM key. Without this, the pcompat_dkim_key entries in the virtual_mta_injected context will be used. |
general {
pcompat_process_x_dkim_options_header yes remove=yes
}
Example headers:
X-DKIM-Options: d=example.com
X-DKIM-Options: [email protected]
X-DKIM-Options: key-list=my-key-list;s=sel1
X-DKIM-Options: key-list=my-key-list;d=example.com ;
[email protected];s=sel1
This directive will prevent GreenArrow from DKIM signing one or more headers in the outgoing email message.
This can be useful when a downstream email provider is changing the value of a header. For example, if the server you’re relaying through assigns a new Message-ID.
Multiple dkim_sign_ignore_header directives can be used to cumulatively add additional header names.
general {
dkim_sign_ignore_header "Message-ID"
}
This directive will instruct GreenArrow to append the given headers to the list
of headers that will be DKIM signed. Except when overrided by dkim_sign_ignore_header,
GreenArrow always signs all headers that would be delivered (i.e. X-GreenArrow-*
headers are not signed).
Using this directive effects the following behavior:
- If the header is not present in the message being signed, its null value will be signed.
- If the header is present in the message being signed, the header value(s) AND a null value will be signed. This means that an extra header cannot be added.
The result is that use of this directive helps to protect against DKIM replay attacks.
Multiple dkim_sign_extra_header directives can be used to cumulatively add additional header names.
general {
dkim_sign_extra_header "Subject", "From", "To", "CC", "Date", "Message-ID"
}
This directive changes the header and body canonicalization used for DKIM signing. GreenArrow has found that “simple” canonicalization offers some performance improvements over the previous default of “relaxed”. For this reason, “simple” has become our new default.
Use this directive to override this behavior and revert to the previous default of “relaxed”.
general {
dkim_sign_canonicalization_mode relaxed
}
Content Replacement
This directive allows you to replace the domain name used in email messages based upon the actual IP address or relay server used to deliver the email.
Prior to using this directive, please read the Replace Content Domain documentation. This page describes the directive, what content is replaced, and various caveats about its usage.
disable_validating_domain_in_tracking_security must be enabled for this feature to function properly with click and open tracking.
ip_address ip-addr-1 {
replace_content_domain greenarrowemail.com
}
This directive causes replace_content_domain to additionally apply
to the domains listed in the From
header.
Prior to using this directive, please read the Replace Content Domain documentation. This page describes the directive, what content is replaced, and various caveats about its usage.
ip_address ip-addr-1 {
replace_content_domain greenarrowemail.com
replace_content_domain_applies_to_from_domain yes
}
This directive causes replace_content_domain to additionally apply
to the domains listed in the Reply-To
header.
Prior to using this directive, please read the Replace Content Domain documentation. This page describes the directive, what content is replaced, and various caveats about its usage.
ip_address ip-addr-1 {
replace_content_domain greenarrowemail.com
replace_content_domain_applies_to_reply_to_domain yes
}
SMTP Pattern Matching
This context defines an SMTP pattern list. SMTP pattern lists contain the smtp_pattern directives.
smtp_pattern_list pattern-1 {
smtp_pattern /no such user/ result=perm_failure
smtp_pattern /try again/ result=temp_failure
}
This directive defines an SMTP pattern regular expression. What GreenArrow does with this pattern is defined by the further options, defined below.
- The first smtp_pattern that matches is used, and no further patterns are evaluated.
- If the matched smtp_pattern includes the
backoff=
option, any smtp_match_begin_backoff_mode directives are not evaluated. - If the matched smtp_pattern includes the
result=
option, any override_smtp_result directives are not evaluated.
The regular expression syntax used is that understood by the Go programming language. While this is mostly a subset of PCRE, there may be a few differences. Please refer to the Go documentation for help with regular expression syntax, or contact technical support.
These options affect what the smtp_pattern will match:
match_smtp_result
string |
Match this smtp_pattern only if the original SMTP result was this (either |
||||||||
match_smtp_code
integers |
Match this smtp_pattern only if we received an SMTP result code and it matches one of those specified.
Multiple codes can be combined using vertical bars like |
||||||||
case_insensitive
boolean /default: |
Match the regular expression case insensitively. |
||||||||
pre_lowercase
boolean /default: |
Lowercase the SMTP result text prior to matching the regular expression. This offers a slight performance improvement when many smtp_match_begin_backoff_mode directives are used. When using this, your regular expression should be written all-lowercase. |
||||||||
match_format
string /default: Match on the specified response format. Valid formats are listed below. See this page for a discussion on the differences between these formats.
|
These options affect what action a match will effect:
result
string |
The new SMTP result that should be used in place of the original result.
May be: The options This option will not override a |
backoff
string |
Update the backoff status for the throttle used for this delivery attempt.
May be: |
skip_mx
boolean |
If the SMTP result is not |
pause
string |
Pause sending for the message’s RFC5321.MailFrom or RFC5322.From domain for messages with a matching recipient domain or in the same throttle grouping. May be: See Pausing Domains for more information. |
These options tune backoff mode, if the pattern engages backoff mode:
backoff_default_duration
duration /default: |
The default time duration to run in backoff mode if no Throttle Program is configured for this throttle. |
backoff_duration
duration |
The time to run in backoff mode, regardless of if a Throttle Program is
configured for this throttle. If this value is specified, it will take precedence over |
backoff_maxconn
integer |
The maximum number of connections to establish while in backoff mode. If this value is specified, it will take precedence over any configured throttle program. |
backoff_msgperhour
integer |
The maximum number of delivery attempts to try per hour while in backoff mode. If this value is specified, it will take precedence over any configured throttle program. |
These options tune domain pausing, if the pattern pauses the domain:
pause_duration
duration /default: |
The length of time the pause will be in effect. |
pause_message
string |
The response to use when pausing deliveries due to the pause. |
smtp_pattern_list pattern-1 {
smtp_pattern /no such user/ result=perm_failure
smtp_pattern /try again/ result=temp_failure
}
This directive instructs GreenArrow to use the specified smtp_pattern_list for this IP/domain combination.
See the domain context for a description of how precedence is determined. The SMTP pattern list for the most specific matched domain will be used.
For example:
smtp_pattern_list pattern-global {
...
}
smtp_pattern_list pattern-yahoo {
...
}
ip_address * {
domain * {
smtp_pattern_list pattern-global
}
domain yahoo.com {
smtp_pattern_list pattern-yahoo
}
}
Given the above configuration; for the domain yahoo.com
, the SMTP pattern list
pattern-yahoo
will be evaluated. For all other domains, the SMTP pattern list
pattern-global
will be evaluated.
This option controls how skip_mx
(as an option to smtp_pattern)
picks the next MX server.
next_mx_record
default |
The remaining IP addresses ( |
next_a_record |
The next IP address ( |
This directive allows you to specify that the RFC5321.MailFrom domain or the RFC5322.From domain of the message should be paused (for messages with a matching recipient domain or in the same throttle grouping) when an SMTP response message matches the specified regular expression.
See Pausing Domains for more information.
smtp_match_pause_domain is not evaluated if an smtp_pattern matched and
that pattern included the pause=
option.
For multiple smtp_match_pause_domain directives, evaluation will be done in order of tighter precedence to broader precedence (as defined in the domain directive). Directives at the same level of precedence will be evaluated in the order they are defined in the configuration file. The first directive to match in this order of evaluation will be used.
Required argument:
regexp |
All remote SMTP response messages will be matched against this regular expression. |
Optional arguments:
type
string /default: |
Determines whether to pause the RFC5321.MailFrom or RFC5322.From domain. Must be one of the following:
|
||||||||
duration
duration /default: |
The length of time the pause will be in effect. |
||||||||
message
string The message to use when pausing deliveries that are determined to be paused. This defaults to one of the following (depending on the
|
|||||||||
case_insensitive
boolean /default: |
Match the regular expression case insensitively. |
||||||||
pre_lowercase
boolean /default: |
Lowercase the SMTP result text prior to matching the regular expression. This offers a slight performance improvement when many smtp_match_pause_domain directives are used. When using this, your regular expression should be written all-lowercase. |
||||||||
match_format
string /default: Match on the specified response format. Valid formats are listed below. See this page for a discussion on the differences between these formats.
|
Example:
ip_address * {
domain * {
smtp_match_pause_domain /try again later/ type=rfc5321_mailfrom_domain case_insensitive=yes message="We were told to try again later"
}
}
Logging
GreenArrow log files are automatically rotated and contain timestamps in external TAI64 format. Refer to the Service Logs documentation for more information on individual log files.
Disk Queue
This option controls GreenArrow’s debug logging for the disk queue (/var/hvmail/log/disk-qmail-send
).
crash
default |
Debug messages will be included in disk queue crash reports (which are
created as This is the recommended setting for most GreenArrow installations. |
always |
Always include extra debug messages in the disk queue’s log. This significantly increases the number of messages logged and can impact performance. It’s recommended to only turn this on while troubleshooting disk queue issues. |
never |
Debug messages are never created. This can slightly increase performance of the disk queue at the expense of making crashes harder to troubleshoot. |
DNS
Log basic information about DNS lookups performed while GreenArrow delivers mail. This is logged to
/var/hvmail/log/rspawn-limiter/current
. This does not log when
GreenArrow’s internal DNS cache is consulted.
This directive cannot apply to mx:
domain rules, because the decision
of whether or not to log DNS occurs prior to making the DNS lookup.
Due to the timing at which most DNS is resolved (that is, the IP address used
for delivery is not yet known), this directive is most effective when applied
to the **super**
or *
ip_address.
greenarrow-remote.6241: dns MX lookup of mail.drh.net resulted in ["mail.drh.net. (10)"]; 0.32ms elapsed
greenarrow-remote.6241: dns A lookup of mail.drh.net. resulted in ["207.99.125.72"]; 1.04ms elapsed
When doing a DNS lookup, GreenArrow Engine will retry a DNS query if it does not receive an answer within a timeout period. Each log line represents the entire process of doing the DNS resolution, so (a) you will not see a separate line for a timeout, and (b) the time spent on timeouts and retries is included in the elapsed time logged.
ip_address * {
domain hotmail.com, msn.com {
log_dns yes
}
}
SMTP
Log information about SMTP connections being opened and closed.
This is logged to /var/hvmail/log/rspawn-limiter/current
.
(123) attempting to deliver message: recipient=<[email protected]> sender=<[email protected]> mtaid=<0> sendid=<DUNNO> listid=<DUNNO> local_ip_address=<207.99.125.72>
(123) attempting to connect: domain=<mail.drh.net.> ip=<207.99.125.72>
(123) connected: domain=<mail.drh.net.> local_addr=<64.21.76.43:33469> remote_addr=<207.99.125.72:26>
(123) connection closed: local_addr=<64.21.76.43:33469> remote_addr=<207.99.125.72:26>
The prefix (123)
is an identifier for the connection. These identifiers are reused.
ip_address * {
domain hotmail.com, msn.com {
log_smtp_connections yes
}
}
Log the SMTP commands and responses exchanged with the remote SMTP
server (along with information about connections being opened/closed).
This does not include message data. This is logged to
/var/hvmail/log/rspawn-limiter/current
.
(123) attempting to deliver message: recipient=<[email protected]> sender=<[email protected]> mtaid=<3> sendid=<a512> listid=<a2> local_ip_address=<default>
(123) attempting to connect: domain=<mail.drh.net> ip=<207.99.125.72>
(123) connected: domain=<mail.drh.net> local_addr=<64.21.76.43:33469> remote_addr=<207.99.125.72:26>
(123) <<< 220 mail.drh.net ESMTP
(123) >>> EHLO localhost
(123) <<< 250-mail.drh.net
(123) <<< 250-AUTH LOGIN PLAIN
(123) <<< 250-AUTH=LOGIN PLAIN
(123) <<< 250-PIPELINING
(123) <<< 250 8BITMIME
(123) >>> MAIL FROM:<[email protected]> BODY=8BITMIME
(123) <<< 250 ok
(123) >>> RCPT TO:<[email protected]>
(123) <<< 553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)
(123) >>> QUIT
(123) <<< 221 mail.drh.net
(123) connection closed: local_addr=<64.21.76.43:33469> remote_addr=<207.99.125.72:26>
The prefix (123)
is an identifier for the connection. These identifiers are reused.
ip_address * {
domain hotmail.com, msn.com {
log_smtp_commands yes
}
}
Log the raw bytes exchanged with the remote SMTP server in a hex-dump
format (along with information about connections being opened/closed).
This includes message data. This is logged to
/var/hvmail/log/rspawn-limiter/current
.
(123) attempting to deliver message: recipient=<[email protected]> sender=<[email protected]> mtaid=<3> sendid=<a512> listid=<a2> local_ip_address=<default>
(123) attempting to connect: domain=<mail.drh.net> ip=<207.99.125.72>
(123) connected: domain=<mail.drh.net> local_addr=<64.21.76.43:33469> remote_addr=<207.99.125.72:26>
(123) <<< received 24 bytes
(123) 32 32 30 20 6d 61 69 6c 2e 64 72 68 2e 6e 65 74 |220 mail.drh.net|
(123) 20 45 53 4d 54 50 0d 0a | ESMTP..|
(123) >>> sent 16 bytes
(123) 45 48 4c 4f 20 6c 6f 63 61 6c 68 6f 73 74 0d 0a |EHLO localhost..|
(123) <<< received 92 bytes
(123) 32 35 30 2d 6d 61 69 6c 2e 64 72 68 2e 6e 65 74 |250-mail.drh.net|
(123) 0d 0a 32 35 30 2d 41 55 54 48 20 4c 4f 47 49 4e |..250-AUTH LOGIN|
(123) 20 50 4c 41 49 4e 0d 0a 32 35 30 2d 41 55 54 48 | PLAIN..250-AUTH|
(123) 3d 4c 4f 47 49 4e 20 50 4c 41 49 4e 0d 0a 32 35 |=LOGIN PLAIN..25|
(123) 30 2d 50 49 50 45 4c 49 4e 49 4e 47 0d 0a 32 35 |0-PIPELINING..25|
(123) 30 20 38 42 49 54 4d 49 4d 45 0d 0a |0 8BITMIME..|
(123) >>> sent 46 bytes
(123) 4d 41 49 4c 20 46 52 4f 4d 3a 3c 73 65 6e 64 65 |MAIL FROM:<sende|
(123) 72 40 65 78 61 6d 70 6c 65 2e 63 6f 6d 3e 20 42 |[email protected]> B|
(123) 4f 44 59 3d 38 42 49 54 4d 49 4d 45 0d 0a |ODY=8BITMIME..|
(123) <<< received 8 bytes
(123) 32 35 30 20 6f 6b 0d 0a |250 ok..|
(123) >>> sent 28 bytes
(123) 52 43 50 54 20 54 4f 3a 3c 75 73 65 72 40 65 78 |RCPT TO:<user@ex|
(123) 61 6d 70 6c 65 2e 63 6f 6d 3e 0d 0a |ample.com>..|
(123) <<< received 71 bytes
(123) 35 35 33 20 73 6f 72 72 79 2c 20 74 68 61 74 20 |553 sorry, that |
(123) 64 6f 6d 61 69 6e 20 69 73 6e 27 74 20 69 6e 20 |domain isn't in |
(123) 6d 79 20 6c 69 73 74 20 6f 66 20 61 6c 6c 6f 77 |my list of allow|
(123) 65 64 20 72 63 70 74 68 6f 73 74 73 20 28 23 35 |ed rcpthosts (#5|
(123) 2e 37 2e 31 29 0d 0a |.7.1)..|
(123) >>> sent 6 bytes
(123) 51 55 49 54 0d 0a |QUIT..|
(123) <<< received 18 bytes
(123) 32 32 31 20 6d 61 69 6c 2e 64 72 68 2e 6e 65 74 |221 mail.drh.net|
(123) 0d 0a |..|
(123) connection closed: local_addr=<64.21.76.43:33469> remote_addr=<207.99.125.72:26>
The prefix (123)
is an identifier for the connection. These identifiers are reused.
ip_address * {
domain hotmail.com, msn.com {
log_smtp_hexdump yes
}
}
Include SMTP timings in the delivery attempt log and related commands such as hvmail_report
.
These timings are presented as a CSV list of timings (in nanoseconds) representing how long each of the following took:
- Time spent processing this request not otherwise covered by the timings listed below.
- Wait for a remote SMTP connection slot (system_max_smtp_connections).
- DNS resolution (this includes both time spent waiting for the DNS concurrency limit and actually waiting for the DNS response).
- Establishing a TCP connection to the remote server.
- Establishing a TCP connection to a proxy server (see proxy_server)
- Establishing a TCP/SMTP connection from the proxy server to the remote server (see proxy_server). This includes reading the remote server’s greeting (this is because reading the remote server greeting is the only way with HA Proxy to know that the TCP connection attempt succeeded).
- Establishing an SMTPS connection to the remote server (due to the remote server port number of 465).
- SMTP Conversation: Reading remote server’s greeting
- SMTP Conversation: EHLO
- SMTP Conversation: STARTTLS
- SMTP Conversation: AUTH
- SMTP Conversation: MAIL FROM
- SMTP Conversation: RCPT TO
- SMTP Conversation: DATA
- SMTP Conversation: Reading message file (if replace_content_domain or the
load_message_before_sending_data
legacy_behavior is in use) - SMTP Conversation: Modifying message data (e.g. modifying the content domain with replace_content_domain or DKIM signing using pcompat_dkim_sign within ip_address)
- SMTP Conversation: Sending message to remote server (this also includes reading the message file unless replace_content_domain or the
load_message_before_sending_data
legacy_behavior is in use) - SMTP Conversation: Waiting for the remote server to acknowledge the received message
- SMTP Conversation: QUIT
- Closing the TCP/SMTP connection to the remote server.
- Time spent closing a connection or waiting for a reusable connection to become free (due to reuse_connections). See a detailed explanation of this field below.
- Time spent waiting for VirtualMTA throttle availability in the backlog queue and time spent spent making the throttle availability decision.
- Number of MX servers connected to for this delivery attempt. This may be more than 1 when the
skip_mx
feature is in use.
Detailed explanation of the 21st field
Sometimes before GreenArrow can open a new connection, GreenArrow must close an existing connection that was being held open due to connection reuse. This field represents the time spent closing a connection or waiting for a reusable connection to become free.
The reason for this possible wait is that: (1) GreenArrow may only reuse a connection if it is to an IP address that is a Mail Exchanger (as listed in the DNS records) for the new email to be delivered, (2) a throttle rule may define a concurrent connection limit (for example no more than 10 concurrent connections) and this throttle rule can contain domains that have different and non-overlapping Mail Exchanger IP addresses (and therefor a connection that delivered one email might not be allowed to deliver the next email).
In the particular case where (a) a throttle rule like this exists, (b) the entire concurrent connection limit is reached (for example, all 10 concurrent connections are used), and (c) none of the connections that are held open for reuse are to an IP that is a Mail Exchanger for the next email to be delivered – then an existing connection will have to be closed before the delivery attempt of this next email is allowed to open a new connection. Or, while waiting for a connection to be closed, an existing connection to an IP address that is a Mail Exchanger for this next email may finish delivering another email and become eligible to be reused for this next email, at which point it will be used.
ip_address * {
domain hotmail.com, msn.com {
log_smtp_timings yes
}
}
Message Processing
Logging and Removing Headers
This directive is used to specify which headers are parsed from the email and
logged to the headers
attribute of the
Delivery Attempt Log
and the delivery_attempt
event.
Header parsing is done at time of message injection, so adjusting this directive will not affect emails already in the queue. Header names are matched case-insensitively. Headers that are folded will be logged including whatever newlines and whitespace are used in folding.
The first email address in the From header is always logged in the from_address
attribute, so unless you explicitly need the entire From header, it is not
necessary to include it here.
Multiple log_header directives can be used to cumulatively add additional header names.
Headers are matched case-insensitively. In keys of the JSON object written to the Delivery Attempt Log and delivery_attempt event, the case of the header is determined by the case used in the log_header directive.
general {
log_header "Subject", "X-Mailer"
log_header "X-Another-Header"
}
This directive is the same as with the same caveats as log_header, except that it will also remove the header from the outgoing message. This means the message as delivered will not include headers configured with this directive.
general {
log_header_remove "X-My-Header"
}
This directive removes headers from messages. Headers are removed case-insensitively.
This directive can be specified multiple times to remove multiple headers.
When this directive is included in both the general context and/or multiple source contexts (irrespective of whether the matching source contexts are broader or narrower), all matching directives will be applied.
In the following example, messages injected from 127.0.0.1
will have all three headers removed
(X-My-Header
, X-Other-Header
, and X-Yet-Another-Header
).
general {
remove_header "X-My-Header"
}
source * {
remove_header "X-Other-Header"
}
source 127.0.0.1 {
remove_header "X-Yet-Another-Header"
}
Message Pattern Matching
When specified on the top-level, this directive defines a new message pattern list.
message_pattern_list pp-01 {
header_pattern X-Foo /bar/ set_virtualmta=discard
}
When specified within a source, this directive will cause the pattern list to be applied to that source. This directive can be specified multiple times (or multiple pattern lists can be specified separated by commas) to apply multiple pattern lists to a source. The pattern lists will be evaluated in order of definition. Pattern list definition and lookup and case-insensitive.
source * {
message_pattern_list pp-01
message_pattern_list pp-02
}
When multiple matching source directives specify message_pattern_list,
the most specific source directive will take effect. For example, in the following
configuration, the IP address 10.0.0.1
will evaluate the p-3
and p-4
pattern lists,
while the IP address 10.0.0.2
will only evaluate p-2
.
source * {
message_pattern_list p-1
}
source 10.0.0.0/24 {
message_pattern_list p-2
}
source 10.0.0.1 {
message_pattern_list p-3, p-4
}
This directive is used to define a message header pattern. Evaluation of header_pattern
regular expressions will stop when one matches (independent of whether or not set_virtualmta
is configured). Patterns are evaluated in the order of definition.
header
may be one of the following:
- A header logged using log_header or log_header_remove.
- A virtual header, defined below. All virtual headers start with a
:
.
:RFC5321.MailFrom |
The RFC5321.MailFrom email address for this message (sometimes known as the MAIL FROM or Return-Path address). |
:RFC5321.MailFrom.Domain |
The RFC5321.MailFrom domain. |
:RFC5322.From |
The RFC5322.From email address for this message (sometimes known as the From header). |
:RFC5322.From.Domain |
The RFC5322.From domain. |
:ClickTrackingID |
The |
:SendID |
The SendID value for this message. |
The header
argument to this directive is evaluated case-insensitively.
The regexp
argument is evaluated case-sensitively.
If a header is specified multiple times in a message, all occurrences of that header are evaluated for a match.
Optional arguments:
set_virtualmta
default: none |
Specify a VirtualMTA ID or name to redirect this mail to the specified VirtualMTA.
To specify the default VirtualMTA, use |
set_virtualmta_precedence
default: |
By default, the |
evaluate_on_retry
default: |
By default, header_pattern is only evaluated upon message injection. If a match is found,
the VirtualMTA specified by This option, when enabled, will cause the pattern to be evaluated upon each retry.
If a match is found, the VirtualMTA specified by The purpose of this option is to enable you to create a new header_pattern that will affect messages that are already in the queue awaiting retry. We recommend that if you use this, you disable it after queue_lifetime has passed (so you know that all messages in the queue have been evaluated). |
decode_rfc2047
default: |
By default, the literal header value will be evaluated. Use this option to RFC2047 decode the value prior to evaluation. |
# Define the message pattern list.
message_pattern_list pp {
header_pattern X-Header /foo/ set_virtualmta=system_default
header_pattern X-Header /bar/ set_virtualmta=ipaddr-1 set_virtualmta_precedence=higher
}
# Apply that pattern list to all messages.
source * {
message_pattern_list pp
}
Legacy
Legacy Behavior
This directive enables legacy behaviors that are no longer the default behavior in GreenArrow.
event_processor_is_retry_as_integer
Prior to GreenArrow v4.295.0, the |
|
noncompliant_smtp_data_dot
Prior to GreenArrow v4.305.0, GreenArrow’s incoming SMTP service was noncompliant
with RFC5321 Section 4.1.1.4
in allowing Starting with GreenArrow v4.305.0, only This option reverts to the noncompliant behavior described above. |
|
do_not_anonymize_sender_localpart_in_events
Prior to GreenArrow v4.308.0, the event_delivery_anonymize_localparts directive
did not apply to |
|
load_message_before_sending_data
Prior to GreenArrow v4.311.0, GreenArrow would load the entire message into memory before transmitting it to a remote server. Now, GreenArrow reads the message from disk and streams it to the remote server (unless that message is due to be customized via the replace_content_domain directive). This saves memory (which can be significant on servers that send many large messages), at the expense of having more files open concurrently. |
|
studio_default_segment_query_cost
Prior to GreenArrow v4.320.0, GreenArrow Studio’s segment SQL queries could sometimes
fail to use indexes that were available, leading to slow segmentation. In v4.320.0, we
tuned some PostgreSQL parameters to avoid this situation. Use this |
|
single_connmaxout_message
Prior to GreenArrow v4.322.0, GreenArrow had a single connmaxout message:
GreenArrow now differentiates between these two connmaxout messages:
This option restores the single connmaxout message. |
|
perl_remote_limiter
Prior to GreenArrow v4.329.0, GreenArrow had an older subsystem for throttling remote delivery attempts. This legacy option reverts to that older subsystem. To apply this option, after updating your
The legacy version of the remote delivery throttling subsystem will not receive further feature updates and will be discontinued on or after November 1, 2024. |
|
studio_no_received_header
Prior to GreenArrow v4.328.0, GreenArrow Marketing Studio did not add a |
|
http_submission_api_no_received_header
Prior to GreenArrow v4.328.0, the HTTP Submission API did not add a |
|
default_statistic_report_grouping_per_instanceid_legacy
This option forces the GreenArrow UI, API, and configuration file to use “Per InstanceID (Legacy)” as the default “Statistic & Report Grouping” value. Prior to GreenArrow VERSION, this was the only available mode. After VERSION, “Per Day” is the default. |
To enable a legacy behavior:
general {
legacy_behavior event_processor_is_retry_as_integer
}
To explicitly disable a legacy behavior (legacy behaviors are disabled by default, so this is usually not necessary):
general {
legacy_behavior event_processor_is_retry_as_integer=no
}
DNS Cache
When this directive is turned on, GreenArrow provides a recursive DNS server on the localhost.
Formerly, GreenArrow required that its own recursive DNS server run on
127.0.0.1
and that /etc/resolv.conf
be configured to query it.
GreenArrow now only requires that a working recursive DNS server be
configured in /etc/resolv.conf
. Configuring this is the responsibility
of the system administrator.
WARNING: Before disabling or enabling this directive, ensure that you will not break DNS resolution on your server. This document provides some advice on how to do this.
System Monitoring
Disk Space Warning Banner
This directive controls the threshold for displaying disk usage warnings in GreenArrow’s web interfaces. You can use multiple instances of this directive:
general {
ui_disk_space_warning_threshold 75%
ui_disk_space_warning_threshold 80% /var/hvmail/postgres
ui_disk_space_warning_threshold 80% /var/hvmail/log
}
The directive is used to control the monitoring of disk space only. Inode usage is not monitored.
The following filesystems are monitored by default:
-
/
. - Any mounted filesystem that uses
brtfs
,ext3
,ext4
reiserfs
orxfs
.
The optional path
argument is used to specify the mount point of a specific
filesystem. If an entry excludes the path
, then it changes the threshold for
all monitored filesystems which don’t have their own
ui_disk_space_warning_threshold
entries:
general {
ui_disk_space_warning_threshold 85%
}
If the path
argument is included, and it matches the mount point of a
filesystem, the filesystem is monitored, regardless of whether it’s in the
default list of monitored filesystems:
general {
ui_disk_space_warning_threshold 85% /media/disk1
}
If no mounted filesystem uses the specified path
as its mount point, the
entry is ignored:
general {
ui_disk_space_warning_threshold 70% /no/such/filesystem
}
To exclude an individual filesystem from monitoring, set its threshold to 100%:
general {
ui_disk_space_warning_threshold 100% /media/disk1
}
To exclude all filesystems from monitoring, either set
ui_disk_space_warning_threshold
to 100% use the
ui_disk_space_warning_hide
directive, which is described in the next section:
general {
ui_disk_space_warning_threshold 100%
}
See the Warning Banner section of Troubleshooting Disk Space Issues for more details.
If ui_disk_space_warning_hide
is set to yes
, then disk space usage banner
is never shown, regardless of the disk usage situation:
general {
ui_disk_space_warning_hide yes
}
See the Warning Banner section of Troubleshooting Disk Space Issues for more details.
TLS Certificates
Let’s Encrypt Integration
Also see:
This directive indicates whether you agree to the Let’s Encrypt subscriber agreement.
GreenArrow can automatically register TLS certificates with Let’s Encrypt, but only if this directive is used to accept the agreement, and lets_encrypt_registration_email is used to indicate who accepted it.
general {
lets_encrypt_agree_to_terms_of_service yes
}
This directive sets the email address to use when agreeing to the Let’s Encrypt subscriber agreement. It only has meaning if lets_encrypt_agree_to_terms_of_service indicates acceptance of the agreement.
See TLS Certificate Configuration for more information about enabling Let’s Encrypt integration.
This email address will receive an Expiration Email from Let’s Encrypt before a certificate will expire. See Expiration Notifications for more information about domain expiration.
general {
lets_encrypt_registration_email "[email protected]"
}
When this directive is enabled or absent:
GreenArrow’s checks whether it’s able to connect to itself via HTTP (port 80) at the URL domain before it attempts to register a TLS certificate with Let’s Encrypt for that domain.
We recommend keeping this setting turned on in most cases because it prevents sending invalid registration requests to Let’s Encrypt. Due to Let’s Encrypt’s rate limits, we aim to only communicate with Let’s Encrypt when we’re confident a request will succeed.
If the self-check fails, an error is logged. These are shown in the URL domains screen in Engine’s user interface.
If your GreenArrow installation has a firewall configuration that prevents
GreenArrow from connecting to its own URL domains, then this self-check doesn’t have
any value and can be disabled by setting this directive to no
.
When this directive is disabled:
GreenArrow will not attempt a self-check before connecting to Let’s Encrypt. In this mode, we rely solely on Let’s Encrypt’s http-01-challenge to confirm that the URL domain and its DNS is correctly configured.
general {
lets_encrypt_certs_self_check yes
}
By default, GreenArrow communicates with the production Let’s Encrypt registration server. If you prefer to communicate with another server, such as Let Encrypt’s staging environment, then populate this parameter with the desired server’s URL.
This field was created for testing on non-production servers. It should not be edited on a production server unless you’re 100% confident that the change won’t have any negative consequences.
general {
lets_encrypt_registration_server https://acme-staging-v02.api.letsencrypt.org/directory
}
After registering or renewing Let’s Encrypt certificates, GreenArrow restarts the Apache and PureFTPd services. In most cases, this is a very low impact restart. However, some servers can be slower to get Apache up and running again.
This directive serves to increase the delay between these restarts. This will cause new certificiates to be loaded less often (and so it’ll take longer for registered or renewed certificates to be in effect).
general {
lets_encrypt_service_restart_delay 1h
}
Other TLS Certificates
This directive specifies the private key, certificate, and optionally, intermediate certificate to use for GreenArrow’s Server-Default TLS Certificate. It has higher precedence than tls_certificate_auto_generate.
All arguments must be absolute filesystem paths, like in the example below.
Relative paths, like cert.pem
, are not supported.
If any of the deprecated default TLS certificate files exist, they will prevent the certificate defined by this directive from taking effect for their relevant service.
See the Default TLS Certificate documentation for more information.
general {
tls_certificate_files /etc/tls/private.key /etc/tls/cert.pem /etc/tls/ca.pem
}
This directive has no effect unless the Let’s Encrypt subscriber agreement has been accepted via lets_encrypt_agree_to_terms_of_service and lets_encrypt_registration_email.
This directive specifies a domain for which GreenArrow should register a TLS certificate with Let’s Encrypt, then use for the Server-Default TLS Certificate. This directive has lower precedence than tls_certificate_files.
If any of the deprecated default TLS certificate files exist, they will prevent the certificate defined by this directive from taking effect for their relevant service.
See the Default TLS Certificate documentation for more information.
general {
tls_certificate_auto_generate example.com
}
GreenArrow Marketing Studio
Studio Sign-in
The length of time that a user can be idle before they will be automatically signed out of GreenArrow Studio. Any regular page navigation within Studio will refresh this timeout. Dynamically reloading pages will not refresh this timeout.
Regardless of how this directive is configured, GreenArrow Studio will always sign out users whose session has been inactive for 30 days or more.
The process that manages these timeouts runs once per minute, so there can be up to that long of a delay after the timeout expires until the user is actually signed out. The (inactive) web browser will not refresh to indicate the user has signed out until the user attempts to interact with another Studio page. At that time, the user would be redirected back to the sign-in page.
general {
studio_user_session_activity_timeout 2h
}
The window of time in which failed sign-in attempts accumulate.
See studio_user_login_lockout_duration for a detailed description of user lockouts.
general {
studio_user_login_lockout_attempt_window 15m
}
The number of failed sign-in attempts during the studio_user_login_lockout_attempt_window window that will cause a lockout.
See studio_user_login_lockout_duration for a detailed description of user lockouts.
general {
studio_user_login_lockout_attempt_count 10
}
The length of time for which the user will be locked-out following an excessive number of failed logins in a window.
If a user attempts (and fails) to sign in at least studio_user_login_lockout_attempt_count number of times within a studio_user_login_lockout_attempt_window window of time, that user will be locked out for the length of time defined by this directive.
If any of these three directives are set to zero, no user lockouts will occur.
Attempts to sign in during the lockout will not result in an extension of the lockout.
When a lockout occurs, previous sign-in attempts are discarded. Once the lockout expires, the user will again have studio_user_login_lockout_attempt_count number of attempts to gain access.
This means that the maximum speed of bad login attempts that one can achieve is:
max(
(studio_user_login_lockout_attempt_count - 1) / studio_user_login_lockout_attempt_window,
studio_user_login_lockout_attempt_count / studio_user_login_lockout_duration
)
So for a max attempts count of 10 and a lockout duration of 15 minutes, a user can make approximately 40 attempts per hour. However, a shorter attempt window can lead to a faster rate of attempts. If in the previous example the window is 5 minutes, then a rate of 108 attempts per hour can theoretically be achieved.
User lockouts do not apply to Studio API keys.
general {
studio_user_login_lockout_duration 15m
}
Log all (successful and failures) user login attempts to the given file. One line will be written to this file per login attempt.
This file must be writable by the apache
system user. The filename must contain
an absolute path (i.e. it begins with /
).
The log file will include entries for the following events:
- An unknown account email address was provided.
- An invalid password was provided.
- An invalid password was provided and the user now locked-out.
- A sign-in attempt was made while the user was locked out.
- A sign-in attempt was successful and the user is now signed-in.
GreenArrow does not rotate this file, so to avoid disk space exhaustion, you should put a rotation system into place. No GreenArrow services need to be restarted after you rotate the file.
Here’s an example of what will be written to that log file:
2020-05-13 19:58:48 user_not_found: Unknown email address. entered_email="asdf" client_ip="1.2.3.4"
2020-05-13 19:59:00 success: Successful sign-in. user_id="5002" user_email="[email protected]". client_ip="192.136.170.88"
2020-05-13 20:01:51 inactive_organization: Attempt to sign into an inactive organization. user_id="5002" user_email="[email protected]" client_ip="1.2.3.4"
2020-05-13 20:02:06 no_password: Blank password, sign-in aborted. entered_email="[email protected]" client_ip="1.2.3.4"
2020-05-13 20:02:42 invalid_password: Invalid password. user_id="5002" user_email="[email protected]" attempt=1 client_ip="1.2.3.4"
2020-05-13 20:02:44 invalid_password: Invalid password. user_id="5002" user_email="[email protected]" attempt=2 client_ip="1.2.3.4"
2020-05-13 20:02:46 invalid_password_locked_out: Invalid password, user is now locked out. user_id="5002" user_email="[email protected]" attempt=3 lockout_expires="May 13, 2020 3:04pm (-0500)" client_ip="1.2.3.4"
2020-05-13 20:02:48 user_locked_out: Refused access due to lock-out. user_id="5002" user_email="[email protected]" lockout_expires="May 13, 2020 3:04pm (-0500)" client_ip="1.2.3.4"
Each line begins with the time, followed by a code indicating the result of the sign-in attempt. The valid codes are:
- user_not_found
- success
- inactive_organization
- no_password
- invalid_password
- invalid_password_locked_out
- user_locked_out
- internal_error_unknown_user_signin_result
general {
studio_user_login_logfile "/var/hvmail/apache/logs/studio_user_login.log"
}
Studio Content Editor
The domain name that should be used by the BEE content editor when retrieving images from Studio.
If Let’s Encrypt integration is enabled, a certificate will be automatically registered for this domain.
general {
bee_images_domain images.greenarrowemail.com
}
Studio Subscriber Management
This configuration directive disables support for deleting subscribers in the Studio UI and API.
general {
studio_disable_subscriber_deletion yes
}
Message Generation
By default, messages generated by GreenArrow Marketing Studio include a “Received:” header that looks like this:
Received: by return-path-domain.com for <[email protected]>;
26 Aug 2024 12:42:56 +0000 (envelope-from <[email protected]>)
This directive allows you to override the first domain included in the header above (the “by” domain).
The recipient email address and envelope-from are unaffected by this directive.
general {
studio_received_header_domain esp.example.com
}
Event Processing
Server Identification
An identifier for this server that will be included in event delivery when configured by event_delivery_destination.
The purpose of this directive is for customers whom have multiple GreenArrow servers to more easily identify from which server the event came.
general {
server_id "server-1.example.com"
}
Click and Open Tracking
This directive disables the inclusion of the domain name in click and open tracking anti-tamper protection.
GreenArrow includes anti-tamper protection in the links created for click tracking, to prevent abuse of the link redirector service. Anti-tamper protection detects if the destination URL, the subscriber, or campaign details are tampered with, and returns an error to the user if the link was modified. By default, the domain name in the link is included in this anti-tamper protection.
Including the domain name in anti-tamper protection is useful for email service providers, where one customer could send a link to themselves, capture that link, modify it to use a different domain name belonging to the ESP or another of the ESP’s customers, and then send spam using the modified link – hijacking a domain’s reputation to which they were never supposed to have access.
Use of this directive is required for replace_content_domain to function properly.
general {
disable_validating_domain_in_tracking_security yes
}
This directive disables the verification of the anti-tamper protection in click and open tracking links. Use of this directive is advised only in emergency situations!
If you keep this option enabled your server WILL eventually be abused by spammers for link redirection and your URI will get blacklisted. This is only used for emergencies while fixing a problem with reverse proxy or load balancer in front of GreenArrow.
For more information on anti-tamper protection, see disable_validating_domain_in_tracking_security.
general {
disable_validating_all_tracking_security yes
}
This directive instructs SimpleMH to automatically generate a
click tracking ID.
Using this directive you may conditionally override the click tracking ID based upon the
presence of the X-GreenArrow-Click-Tracking-ID
header (see the table below).
The automatically generated click tracking ID is 32 random hexadecimal
characters (0-9a-f
) and is unique per injected message.
always |
Always generate a click tracking ID, overriding anything the incoming
email has specified for |
never |
Never generate a click tracking ID. If |
if_not_provided |
Generate a click tracking ID only if the incoming email does not include
a value for |
general {
simplemh_generate_click_tracking_id if_not_provided
}
Specify the default expiration time for SimpleMH click and open tracking links. After this time has
elapsed from when the email containing this link was sent, the click or open will receive a simple link expired
message
instead of an open image or redirect. The event will not be recorded.
This expiration can be overridden by Link Replacements.
For links sent using GreenArrow versions prior to v4.304.0, GreenArrow marks the time the upgrade to v4.304.0
or later was performed. Such links will expire at time_of_upgrade + simplemh_default_link_expiration
. This is done
because prior to v4.304.0 the time the email was sent is not included in the link, and thus not available to the
click/open tracker.
general {
simplemh_default_link_expiration 60d
}
Specify the database_connection to use for External Metadata Event Tracking.
If this directive is not configured, any messages that would otherwise use External Metadata Event Tracking will instead use Stateless Metadata Event Tracking.
After changing the database connection’s configuration (either in the UI, API, or configuration file),
you must run greenarrow_config reload
for those changes to take effect.
Optional argument:
table
string |
The name of the table to use in the remote database. If this is not
specified, the table name |
general {
external_metadata_event_tracking_database extpostgres table=greenarrow_data
define_database_connections_in_config_file yes
}
database_connection extpostgres {
database_type postgres
database_name greenarrow
is_remote yes
database_username greenarrow
database_password abcdef123456
}
This directive configures the system default Event Tracking Metadata Storage.
The default for this is ordinarily local
. However, some systems may have a legacy configuration
file /var/hvmail/control/opt.simplemh_stateless_event_handling
set to 1
. In that case, the
default is stateless
. This directive takes precedence over the legacy configuration file.
Available options:
local | |
stateless | |
external |
general {
default_event_tracking_metadata_storage external
}
Bounce & FBL Processing
Email to addresses matching this directive will be processed by the Bounce Processor as a bounce email. Additionally, email to email addresses matching this directive will be accepted by the SMTP server from clients that are not authenticated to relay.
If the optional local_domains_only
parameter is enabled, then only email to
Incoming Email Domains will
be considered for matching.
The regular expression must include, immediately to the left of the @
sign, the value
[[:greenarrow_verp:]]
. This will be replaced by the correct expression for matching GreenArrow’s
VERP syntax. As GreenArrow’s VERP syntax is the only format recognized by the
Bounce Processor
as a bounce email, this ensures that messages matched by this directive will be processed.
Addresses configured with local_domains_only=yes
are only evaluated at the time of injection.
This means that if you’ve got mail already in the queue that might otherwise match a new
application of this directive, it only applies to newly injected messages. This is not the case
when local_domains_only=no
– mail already in the queue will be checked to see if the regular
expression matches when a delivery attempt is made.
The matching performed by this directive is case-insensitive. The regular expression must be fully
anchored, meaning it must begin with ^
and end with $
.
This directive may be specified multiple times to match multiple regular expressions.
This directive takes precedence over any other local delivery rules such as Incoming Email Domain user mailboxes, forwards, bounce mailboxes, and spam complaint mailboxes.
This directive can only be used with GreenArrow’s VERP. Under ordinary situations, this directive tends to not be needed. Most of the time, you’d instead define your bounce mailboxes on Incoming Email Domains. The exception would be if for some reason you don’t want to declare all of your Incoming Email Domains in GreenArrow.
There are two ways to use this feature:
-
If you set simplemh_validate_bounce_address to
no
, then you can enter any bounce address you like for the Bounce Address on your Mail Class (you are not restricted to only those bounce mailboxes configured on Incoming Email Domains). -
You can specify any bounce address using the SimpleMH header
X-GreenArrow-BounceMailboxOverride
.
For example, you might specify your bounce address using the header:
X-GreenArrow-BounceMailboxOverride: [email protected]
Then, define a regular expression like this:
general {
bounce_processor_address /^bounces[[:greenarrow_verp:]]@[^@]*$/ local_domains_only=no
}
The above regular expression will match bounces in GreenArrow’s VERP syntax, for example, any of the following would be matched (this is not a comprehensive list of GreenArrow VERP syntaxes):
[email protected]
[email protected]
bounces-customer-mc0scoped1234-5678601-31627f=2@domain.example.com
Be aware that regardless of how you configure your bounce address, its domain will need to have its MX
record pointing back to the server on which you are processing bounces.
Email to addresses matching this directive will be processed by the Lite Bounce Processor as a bounce email. Additionally, email to email addresses matching this directive will be accepted by the SMTP server from clients that are not authenticated to relay.
If the optional local_domains_only
parameter is enabled, then only email to
Incoming Email Domains will
be considered for matching.
It can be dangerous to exclude local_domains_only=yes
and use non-specific regular expressions.
If your regex is ^bounce@.*$
and local_domains_only
is off, then your system will not be able
to email any external address that is bounce@
at any domain – you can prevent your ability to
email legitimate email addresses. This is why in our example bounce addresses we have the specific
format of the hex identifiers.
Addresses configured with local_domains_only=yes
are only evaluated at the time of injection.
This means that if you’ve got mail already in the queue that might otherwise match a new
application of this directive, it only applies to newly injected messages. This is not the case
when local_domains_only=no
– mail already in the queue will be checked to see if the regular
expression matches when a delivery attempt is made.
The matching performed by this directive is case-insensitive. The regular expression must be fully
anchored, meaning it must begin with ^
and end with $
.
This directive may be specified multiple times to match multiple formats.
This directive takes precedence over any other local delivery rules such as Incoming Email Domain user mailboxes, forwards, bounce mailboxes, and spam complaint mailboxes.
general {
lite_bounce_processor_address /^b-[0-9a-fA-F]{8}-[0-9a-fA-F]{16}@[^@]*$/ local_domains_only=yes
}
This directive cause the bounce_lite
events triggered by matching the
lite_bounce_processor_address directive to include the full message text
of the bounce message in the event. This will be included in the event
as the report_message_text
attribute.
Since bounce messages can sometimes be large, this is disabled by default.
general {
lite_bounce_processor_address /^b-[0-9a-fA-F]{8}-[0-9a-fA-F]{16}@[^@]*$/ local_domains_only=yes
lite_bounce_processor_include_report_text yes
}
This directive instructs GreenArrow to forward messages that match a lite_bounce_processor_address but bounce analysis results in one of the following bounce codes:
-
0
(Non-bounce) -
60
(Auto-reply) -
100
(Challenge response)
In the above cases, the bounce_lite
event is still created. This directive causes
those messages to be forwarded to the specified email address in addition to creating
the bounce_lite
event.
general {
lite_bounce_processor_address /^b-[0-9a-fA-F]{8}-[0-9a-fA-F]{16}@[^@]*$/ local_domains_only=yes
lite_bounce_processor_forward_errors_to yes
}
This directive is used to apply back pressure to the rest of the MTA if more than the configured number of bounces or FBL messages accumulate in the bounce processor’s queue. This back pressure slows down the MTA and can impact both GreenArrow’s delivery and message acceptance performance.
Back pressure is applied in the form of a queueing delay. This is done to prevent larger issues, like memory exhaustion or never catching up on bounce processing from occurring.
The soft limit is reached when the number of messages in the Lite Bounce Processor’s queue exceeds the value set in this directive. When this happens, a small amount of latency is added to the process of queueing new bounces.
general {
lite_bounce_processor_queue_size_soft 5000
lite_bounce_processor_queue_size_hard 10000
}
See lite_bounce_processor_queue_size_soft.
The hard limit is reached when the number of messages in the Lite Bounce Processor’s queue exceeds the value set in this directive. When this happens, the queueing of new bounces is delayed until after the number of messages in the Lite Bounce Processor’s queue falls below the hard limit.
general {
lite_bounce_processor_queue_size_soft 5000
lite_bounce_processor_queue_size_hard 10000
}
Email to addresses matching this directive will be processed by the Lite Bounce Processor as a spam complaint email. Additionally, email to email addresses matching this directive will be accepted by the SMTP server from clients that are not authenticated to relay.
If the optional local_domains_only
parameter is enabled, then only email to
Incoming Email Domains will
be considered for matching.
It can be dangerous to exclude local_domains_only=yes
and use non-specific regular expressions.
If your regex is ^scomp@.*$
and local_domains_only
is off, then your system will not be able
to email any external address that is scomp@
at any domain – you can prevent your ability to
email legitimate email addresses.
Addresses configured with local_domains_only=yes
are only evaluated at the time of injection.
This means that if you’ve got mail already in the queue that might otherwise match a new
application of this directive, it only applies to newly injected messages. This is not the case
when local_domains_only=no
– mail already in the queue will be checked to see if the regular
expression matches when a delivery attempt is made.
The matching performed by this directive is case-insensitive. The regular expression must be fully
anchored, meaning it must begin with ^
and end with $
.
This directive may be specified multiple times to match multiple formats.
This directive takes precedence over any other local delivery rules such as Incoming Email Domain user mailboxes, forwards, bounce mailboxes, and spam complaint mailboxes.
general {
lite_fbl_processor_address /^fbl@[^@]*$/ local_domains_only=yes
}
This directive instructs GreenArrow as to what headers should be extracted from FBL messages processed as a result of the lite_fbl_processor_address directive.
These headers will be included in the scomp_lite
event as the
headers
value.
general {
lite_fbl_processor_address /^scomp@[^@]*$/ local_domains_only=yes
lite_fbl_processor_headers "X-Recip-Info", "X-Sender-Info"
}
This directive cause the scomp_lite
events triggered by matching the
lite_fbl_processor_address directive to include the full message text
of the FBL message in the event. This will be included in the event
as the report_message_text
attribute.
Since FBL messages can sometimes be large, this is disabled by default.
general {
lite_fbl_processor_address /^scomp@[^@]*$/ local_domains_only=yes
lite_fbl_processor_include_report_text yes
}
This directive instructs GreenArrow to forward messages that match a lite_fbl_processor_address but cannot be parsed as FBL complaints to the specified email address.
This includes messages that were received that contained no identifying information.
This happens for one of two reasons:
- GreenArrow was not able to parse the ARF format, or
- The ARF was parsed correctly, but we did not come up with any identifying information (none of the following could be determined: the original message recipient, the original message RFC5321.MailFrom, nor any of the headers configured with lite_fbl_processor_headers were found).
Messages forwarded in this way will be modified to include a header
X-GreenArrowLiteComplaintProcessorError
which explains why the email
could not be parsed.
This directive applies only to the Lite Bounce/Complaint Processor. If you’re using the Full Bounce/Complaint Processor (i.e. you allow GreenArrow to rewrite your RFC5321.MailFrom), you’ll want to use the fbl_processor_forward_errors_to directive instead.
general {
lite_fbl_processor_address /^scomp@[^@]*$/ local_domains_only=yes
lite_fbl_processor_forward_errors_to [email protected]
}
This directive instructs GreenArrow to forward messages that are received by a Spam Complaint Mailbox but cannot be successfully processed as a spam complaint.
Messages that can be processed as a GreenArrow spam complaint contain a copy
of the X-Mailer-Info
header from the original message. All other messages will
be forwarded to the email address configured in this directive.
This directive applies only to the Full Bounce/Complaint Processor (i.e. you allow GreenArrow to rewrite your RFC5321.MailFrom). If you’re using the Lite Bounce/Complaint Processor, you’ll want to use the lite_fbl_processor_forward_errors_to directive instead.
general {
fbl_processor_forward_errors_to [email protected]
}
Event Delivery
All Destination Types
This grouping directive defines an event delivery destination.
See the following directives for more detailed information on configuration particular types of destinations:
- event_delivery_url (HTTP/HTTPS endpoints)
- event_delivery_logfile (Local logfiles)
- event_delivery_sql_dsn (SQL database servers)
- event_delivery_pipe_command (Forked-off processes)
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_events "all"
}
By default (when this directive is either not specified, or if it is set to
no
) GreenArrow’s event processor (service /service/hvmail-event-processor2
)
runs as the system user hvqmaill
. This directive overrides this behavior and
causes that service to run as root
.
After enabling this configuration directive, you need to restart the event processor service for it to take effect:
svc -t /service/hvmail-event-processor2
This directive most prominently affects the following configuration directives:
general {
event_delivery_run_as_root yes
}
List which events you would like to receive to this event delivery destination.
Valid events include:
all
-
none
(may not be combined with other event types) bounce_all
-
bounce_all.engine
(if you only want to receive SimpleMH events) -
bounce_all.studio
(if you only want to receive Studio events) bounce_bad_address
-
bounce_bad_address.engine
(if you only want to receive SimpleMH events) -
bounce_bad_address.studio
(if you only want to receive Studio events) bounce_lite
scomp
-
scomp.engine
(if you only want to receive SimpleMH events) -
scomp.studio
(if you only want to receive Studio events) scomp_lite
engine_click
engine_open
engine_unsub
delivery_attempt
studio_click
studio_open
studio_unsub
studio_subscriber_created
studio_subscriber_updated
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_events engine_open, engine_click, delivery_attempt
}
Or for example if you’d like to receive all but delivery_attempt
events:
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_events all, delivery_attempt=no
}
For the delivery_attempt
event, this directive configures which delivery attempts
will result in events being delivered to the endpoint. Take note that you only need
to specify the options for which you want to override the default value.
all
boolean |
Enable (or disable) all options available to this directive. |
status_success
boolean, default: |
The delivery attempt ended in success. |
status_deferral
boolean, default: |
The delivery attempt ended in deferral. |
status_failure
boolean, default: |
The delivery attempt ended in failure for a reason other than message expiration. |
status_failure_toolong
boolean, default: |
The delivery attempt ended in failure due to message expiration (see queue_lifetime). |
status_connmaxout
boolean, default: |
The delivery attempt ended in deferral because of delivery attempt throttling. |
include_first_attempt_regardless_of_status
boolean, default: |
Include the first attempt of all messages, regardless of the status. |
include_local_channel
boolean, default: |
Include local delivery attempts. |
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_events "delivery_attempt"
event_delivery_delivery_attempt_config status_deferral=yes status_connmaxout=yes
}
The localpart of email addresses should be anonymized before posting to the event delivery destination. This anonymization is stable – meaning that the same plaintext email address will always generate the same anonymized email address.
The sender
field (RFC5321.MailFrom) of delivery_attempt
events will also have its localpart
anonymized, unless do_not_anonymize_sender_localpart_in_events
is configured
using legacy_behavior. This is because GreenArrow’s VERP can
contain the recipient email address.
The anonymized email addresses will look like this (the original domain name is retained):
You can use GreenArrow’s send database to reverse the anonymization on the command-line by providing the sendid and anonymized email address:
$ greenarrow events lookup_anonymized_email_address default221013 [email protected]
Found email address: [email protected]
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_events "all"
event_delivery_anonymize_localparts yes
}
When this directive is enabled, events that contain a non-blank click_tracking_id
will have the click_tracking_id
hashed using event_anonymization_constant.
The resulting value will look like this:
anon.ac7988bcb5d4f442c8b78bf5f4a33367
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_events "all"
event_delivery_anonymize_clicktrackingid yes
}
The directive event_delivery_anonymize_localparts uses this constant to seed the anonymization. If none is provided in this directive, then GreenArrow will use a predetermined constant for the anonymization.
If you have multiple servers and want the anonymization to be distinct between the servers, you would set this directive to different values on each server. If you have multiple servers and want the anonymization to be stable between the servers, you would set this directive to the same value on each server.
general {
event_anonymization_constant "my-secret-value-123"
}
Add extra logging to /var/hvmail/log/event-processor2
for each delivery
attempt. This is useful for diagnosing problems with event delivery. We don’t
recommend that you leave this on full-time once successful event delivery has
been established, as it may obscure meaningful messages in the log.
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_log_verbose yes
}
This directive is a list of mx_hostname
values (as reported in the
delivery_attempt
event) for which you do not wish to deliver those
delivery_attempt
events.
An example of when this might be useful: Some of your mail is relayed to
another SMTP server (e.g. smtp.example.com
) and some of your mail is sent
directly from GreenArrow. If you want to receive delivery_attempt
events for
the mail that is delivered directly, but not for mail relayed to
smtp.example.com
, you would use the example configuration below.
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_exclude_delivery_attempts_to_mx_hostname "smtp.example.com"
}
Specify the format of events to be delivered.
json |
This is the default option for event delivery. This format is supported for HTTP, Logfile, and Pipe Command delivery destinations. The Content-Type of a HTTP POST will be The content will be a JSON document (either an array of objects or a single object, depending on whether or not event_delivery_disable_batching is configured). |
form |
This format is only supported for HTTP delivery destinations. The Content-Type of the HTTP POST will be The content will be an application/x-www-form-urlencoded encoded string. The directive event_delivery_disable_batching must be enabled to use this format. |
csv |
This format is supported for HTTP, Logfile, and Pipe Command delivery destinations. This format is conformant to RFC 4180, with the following clarifications:
The following directive is required when using CSV: The following directives are optional when using CSV: |
delivery_log_json |
This format is supported only for Logfile and Pipe Command delivery destinations and only if the destination receives only |
delivery_log_human |
This format is supported only for Logfile and Pipe Command delivery destinations and only if the destination receives only This is the same format as |
delivery_log_processed |
This format is supported only for Logfile and Pipe Command delivery destinations and only if the destination receives only This is the same format as |
We recommend new integrations use the default of json
. The form
format is
supported because the legacy event processor used this format by default.
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_format json
}
Specify whether or not the POST from the event processor should include all columns, or only the relevant columns for this event type. By default, GreenArrow will only transmit the relevant columns, reducing the size of document that must be parsed by the receiving server.
We recommend new integrations use the default of no
. This option is supported
because the legacy event processor transmitted all columns.
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_serialize_all_columns yes
}
Restrict this event delivery destination to the listed mail classes or exclude the listed mail classes from this event delivery destination. You may not specify both event_delivery_filter_mail_class inclusions and exclusions in the same event_delivery_destination. See the section above Option Flags Encoding for more information on this directive’s syntax. Mail class names are case-insensitive.
By default, mail classes specified are considered inclusions, meaning this event destination will only receive events for the listed mail classes.
To exclude mail classes (meaning this event destination will receive events
for all mail classes except the listed mail classes), append each mail class name with =no
.
Multiple instances of this directive stack, meaning subsequent directives don’t override earlier directives – they instead add to the earlier directives.
To require one or more explicit mail classes:
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_filter_mail_class transactional, secondary
}
To deliver for all mail classes except those explicitly excluded:
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_filter_mail_class transactional=no, secondary=no
}
Restrict this event delivery destination to the listed listids or exclude the listed listids from this event delivery destination. You may not specify both event_delivery_filter_listid inclusions and exclusions in the same event_delivery_destination. See the section above Option Flags Encoding for more information on this directive’s syntax. Listids are case-insensitive.
By default, listids specified are considered inclusions, meaning this event destination will only receive events for the listed listids.
To exclude listids (meaning this event destination will receive events
for all listids except the listed listids), append each listid with =no
.
Multiple instances of this directive stack, meaning subsequent directives don’t override earlier directives – they instead add to the earlier directives.
To require one or more explicit listids:
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_filter_listid t1, a1
}
To deliver for all listids except those explicitly excluded:
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_filter_listid t1=no, a1=no
}
HTTP/HTTPS
The URL of this event delivery destination. This should begin with http://
or https://
.
This cannot be combined with event_delivery_logfile or its associated directives on a single event_delivery_destination (however you may certainly have multiple destinations with different delivery mechanisms).
The following directives are available to tune how HTTP delivery is accomplished:
- event_delivery_max_concurrent_connections
- event_delivery_max_batch_size
- event_delivery_client_certificate_file
- event_delivery_verify_peer
- event_delivery_disable_batching
- event_delivery_http_keepalive
- event_delivery_http_user_agent
The following directives are more general directives that also apply to HTTP destinations:
- event_delivery_events
- event_delivery_delivery_attempt_config
- event_delivery_anonymize_localparts
- event_anonymization_constant
- event_delivery_log_verbose
- event_delivery_exclude_delivery_attempts_to_mx_hostname
- event_delivery_format
- event_delivery_serialize_all_columns
- event_delivery_filter_mail_class
- event_delivery_filter_listid
- event_delivery_timeout
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_events all
}
The number of connections which GreenArrow should open to the configured
endpoint to deliver concurrently. Given that a low value of 1
is the
default, this should be tuned to what your event destination is capable
of handling.
This value must be between 1
and 250
(inclusive).
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_max_concurrent_connections 4
}
The maximum number of events that GreenArrow will write into a single payload (a JSON array) when delivering events to the endpoint.
This value must be between 1
and 1000
(inclusive).
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_max_batch_size 25
}
For HTTP destinations:
Default: 30 seconds
The maximum length of time GreenArrow will wait for the HTTP endpoint to respond to the JSON POST. If the endpoint does not respond in this duration, the events in the batch will be retried.
For SQL destinations:
Default: 5 minutes
The maximum length of time GreenArrow will wait for the remote SQL service to respond after calling its configured SQL query (including the initial connection). If the remote SQL service does not respond in this duration, the event in the query will be retried.
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_timeout 5s
}
When these key and certificate files are configured, the provided HTTPS client certificate will be used when establishing the HTTPS connection to make the POST request. It’s up to the destination server whether or not this leads to authorization.
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_client_certificate_file /root/events_client_key.txt /root/events_client_certificate.txt
}
Instruct the event processor whether it should verify the server’s HTTPS certificate. This is the default behavior and only needs to be specified if you want to disable verification.
This is useful if you’re delivering to a server that uses a self-signed certificate.
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_verify_peer no
}
Disable event delivery batching for HTTP/HTTPS endpoints. This will cause JSON
payloads to submit a single JSON object instead of a JSON array. This directive
is required if event_delivery_format is set to form
.
We recommend new integrations do not enable this directive. Using batching can significantly increase event delivery throughput.
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_disable_batching yes
}
Enable HTTP Keep-Alive for HTTP/HTTPS endpoints. The default value of yes
will cause the event processor to re-use the same connection for multiple
events / event batches, increasing event delivery throughput.
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_http_keepalive no
}
The User-Agent header to send to HTTP/HTTPS endpoints. When not specified, a default value of GreenArrow
will be used.
This value cannot be blank.
event_delivery_destination primary {
event_delivery_url "https://example.com/primary-endpoint"
event_delivery_http_user_agent "custom-ua/1.0"
}
Logfile
Specify a logfile to which this destination should write its events. This
filename must be absolute (it must begin with /
).
The event processor runs as the user hvqmaill
(unless you’ve specified the
event_delivery_run_as_root directive). As such, the paths specified for
writing using the event_delivery_logfile and
event_delivery_logfile_move_to directives must be writable by the
hvqmaill
user.
This cannot be combined with event_delivery_url or its associated directives on a single event_delivery_destination (however you may certainly have multiple destinations with different delivery mechanisms).
It’s safe to move the file that GreenArrow writes events to. If the file that GreenArrow is writing to is moved, GreenArrow detects the move within one second and starts writing events to a new file. Because of this, if you’re using a logfile rotation system, such as syslog, we recommend configuring it to sleep for 1 second between the time that it moves a log file and the time that it deletes, or compresses it, to ensure that no events are lost.
Events are ordinarily delivered to the logfile in JSON formatting (see the event_delivery_format directive). Each line contains a single JSON object representing an event. Each event contains at least the following keys, in the same order as shown in the table:
time_written_to_logfile
float |
A timestamp of when the event was written to the file, in seconds past
the Unix epoch. If the Event Processor’s
filename_append_date setting
is turned on, the date portion of Unless the system clock jumps backward, |
id
integer |
The primary key for the event. |
event_time
integer |
The time that the event occurred, in seconds past the Unix epoch. |
event_type
string |
A short string that names the type of event. If you ever receive an |
The following directives are available to tune how logfile delivery is accomplished:
- event_delivery_logfile_rotation
- event_delivery_logfile_delete_after_days
- event_delivery_logfile_move_to
- event_delivery_logfile_move_interval
- event_delivery_logfile_max_size
- event_delivery_logfile_world_readable
- event_delivery_logfile_fsync_frequency
- event_delivery_logfile_write_empty_batches
- event_delivery_logfile_require_fsync
The following directives are more general directives that also apply to logfile destinations:
- event_delivery_events
- event_delivery_delivery_attempt_config
- event_delivery_anonymize_localparts
- event_anonymization_constant
- event_delivery_exclude_delivery_attempts_to_mx_hostname
- event_delivery_format
- event_delivery_serialize_all_columns
- event_delivery_filter_mail_class
- event_delivery_filter_listid
event_delivery_destination logfile {
event_delivery_logfile /var/log/events.log
event_delivery_logfile_rotation auto
event_delivery_logfile_delete_after_days 30
}
Valid values include: none
, append_date
, and auto
.
none |
No automatic file rotation will occur.
|
append_date |
The date will be appended to the logfile filename.
|
auto |
Automatic file rotation will occur.
|
In all cases, if you rename or delete (e.g. with mv
or rm
) the file that
GreenArrow is writing to, GreenArrow will detect this and reopen the logfile
using the name specified in event_delivery_logfile.
Logfiles are only created when events occur. This means that if no events occur
during a time window (for example, a specific date with
event_delivery_logfile_rotation=append_date
), then no file will be emitted for
that time window.
event_delivery_destination logfile {
event_delivery_logfile /var/log/events.log
event_delivery_logfile_rotation auto
event_delivery_logfile_delete_after_days 30
}
This directive causes GreenArrow to automatically delete old logfile batch files created by the event_delivery_logfile_rotation directive N days after the batch was created.
GreenArrow will look for logfiles to delete in both the parent directory of event_delivery_logfile and event_delivery_logfile_move_to (if configured).
Files are deleted based upon their filename containing the YYYY-MM-DD
date
they were written. As such, this cannot be combined with
event_delivery_logfile_rotation none
.
event_delivery_destination logfile {
event_delivery_logfile /var/log/events.log
event_delivery_logfile_rotation auto
event_delivery_logfile_delete_after_days 30
}
This directive specifies a path to move files to after rotating the current
logfile. This path must be absolute (begin with /
) and must exist as a
writable directory. This path must be writable by either hvqmaill
or root
,
depending on the event_delivery_run_as_root setting (by default hvqmaill
).
Can only be set if event_delivery_logfile_rotation is set to auto
.
If event_delivery_logfile_move_to is specified to a different mounted filesystem than event_delivery_logfile, the file move is non-atomic. In this case, this is the procedure that GreenArrow follows in moving the file:
- The batch file is copied to
${event_delivery_logfile_move_to}/${batch_filename}.new-batch
. - This new file is renamed to
${event_delivery_logfile_move_to}/${batch_filename}
(removing the.new-logfile
suffix). - The original file event_delivery_logfile is deleted.
Any integration that is monitoring for new batch files should ignore any files that end in .new-batch
.
event_delivery_destination logfile {
event_delivery_logfile /var/log/events.log
event_delivery_logfile_rotation auto
event_delivery_logfile_delete_after_days 30
event_delivery_logfile_move_to /var/log/archive/
}
This directive specifies a time interval in which the current logfile will be
rotated. This time interval is evenly distributed starting at 12:00am
. This means
that for a value of 15m
, rotation will occur at 12:00am
, 12:15am
,
12:30am
, etc. If the configured value does not evenly divide into a 24 hour
schedule, the final “batch” of the day will represent less than this length of
time. Because batches are always closed when the date changes, values greater
than 24h
are not supported.
Can only be set if event_delivery_logfile_rotation is set to auto
.
event_delivery_destination logfile {
event_delivery_logfile /var/log/events.log
event_delivery_logfile_rotation auto
event_delivery_logfile_delete_after_days 30
event_delivery_logfile_move_interval 15m
}
This directive specifies the maximum file size to which GreenArrow should allow each logfile batch to grow. If writing an event to the logfile would exceed this size, the current logfile is rotated and a new file will be written.
File sizes may be configured with the following suffixes:
-
b
(bytes) -
kb
(kilobytes) -
mb
(megabytes) -
gb
(gigabytes) -
tb
(terabytes) -
pb
(petabytes)
Can only be set if event_delivery_logfile_rotation is set to auto
.
event_delivery_destination logfile {
event_delivery_logfile /var/log/events.log
event_delivery_logfile_rotation auto
event_delivery_logfile_delete_after_days 30
event_delivery_logfile_max_size 100mb
}
This directive specifies the permissions of the logfile. If this is not set,
the logfile will be created with UNIX permissions 0600
. If this is set, the
logfile will be created with UNIX permissions 0644
.
The logfiles generated by the Event Processor are written as and owned by either
the hvqmaill
or root
system user (depending on the event_delivery_run_as_root setting).
event_delivery_destination logfile {
event_delivery_logfile /var/log/events.log
event_delivery_logfile_rotation auto
event_delivery_logfile_delete_after_days 30
event_delivery_logfile_world_readable yes
}
Can be one of the following: never
, every_second
.
This directive controls how often GreenArrow will fsync()
the logfile.
By default, this occurs once per second. Setting this option to never
can
improve logfile delivery performance, but is rarely recommended.
This option will also fsync()
the event_delivery_logfile and
event_delivery_logfile_move_to directories after creating, moving,
or deleting files from those directories.
The option event_delivery_logfile_require_fsync is available to control
whether or not an fsync()
is required to acknowledge events as delivered. We
recommend leaving these directives at their default values.
event_delivery_destination logfile {
event_delivery_logfile /var/log/events.log
event_delivery_logfile_rotation auto
event_delivery_logfile_delete_after_days 30
event_delivery_logfile_fsync_frequency never
}
In combination with an event_delivery_logfile_rotation of auto
, this
will allow empty batches to be written. This is useful for integrations that
want to know that a batch was created whether or not it included any events.
event_delivery_destination logfile {
event_delivery_logfile /var/log/events.log
event_delivery_logfile_rotation auto
event_delivery_logfile_write_empty_batches yes
}
This directive controls when GreenArrow considers the event to be written to the
logfile (and thus considered delivered). When this directive is enabled,
GreenArrow will not remove events from the queue until GreenArrow successfully
called fsync()
on the logfile after writing the event.
This option increases durability and is recommended in most cases.
This option must be disabled when event_delivery_logfile_fsync_frequency is set to never
.
event_delivery_destination logfile {
event_delivery_logfile /var/log/events.log
event_delivery_logfile_rotation auto
event_delivery_logfile_require_fsync yes
}
Command Pipes
Specify a command that GreenArrow will execute and write events to the STDIN of the command.
The command must have the following attributes:
- It must be an absolute path (it must begin with
/
). - It must be a regular file (or a symlink to a regular file).
- It may contain extra arguments (see example below).
Additionally, depending on the event_delivery_run_as_root configuration setting (which is off by default):
- If event_delivery_run_as_root is enabled:
- It must be owned by
root
. - It must be executable by
root
. - This program is run by the
root
user.
- It must be owned by
- If event_delivery_run_as_root is not enabled:
- It may be owned by any user.
- It must be executable by
hvqmaill
. - This program is run by the
hvqmaill
user.
Event data is written to the program’s STDIN. Events are ordinarily written to the program in JSON formatting with each line containing a single JSON object representing each event. See the event_delivery_format directive for event formatting options.
By default the event delivery is unreliable as each event is considered “delivered” by GreenArrow once it has been written to the Linux operating system pipe that is being read by this command. This means that if the command crashes before reading or processing the events, those events will be lost. For a reliable delivery option see the event_delivery_pipe_ack_mode and event_delivery_pipe_batch_duration directives.
The following directives are available to tune how pipe delivery is accomplished:
The following directives are more general directives that also apply to logfile destinations:
- event_delivery_events
- event_delivery_delivery_attempt_config
- event_delivery_anonymize_localparts
- event_anonymization_constant
- event_delivery_exclude_delivery_attempts_to_mx_hostname
- event_delivery_format
- event_delivery_serialize_all_columns
- event_delivery_filter_mail_class
- event_delivery_filter_listid
event_delivery_destination pipe {
event_delivery_pipe_command /root/deliver_events
event_delivery_pipe_batch_duration 5s
event_delivery_pipe_ack_mode exit_status
}
If you need to provide command-line arguments to your pipe command, shell quoting syntax is supported:
event_delivery_destination pipe {
event_delivery_pipe_command `/root/deliver_events 'argument one' "argument two" argument-3`
event_delivery_pipe_batch_duration 5s
event_delivery_pipe_ack_mode exit_status
}
This directive controls how often GreenArrow will close STDIN to the event_delivery_pipe_command command and wait for it to exit.
When used with an event_delivery_pipe_ack_mode of exit_status
:
- The exit code serves as indication that the events were successfully received by the command.
- GreenArrow warns against durations greater than 10s.
- GreenArrow will refuse to accept durations greater than 1m.
event_delivery_destination pipe {
event_delivery_pipe_command /root/deliver_events
event_delivery_pipe_batch_duration 5s
event_delivery_pipe_ack_mode exit_status
}
This directive controls how GreenArrow decides that an event has been received by the event_delivery_pipe_command.
no_ack |
GreenArrow will consider the event successfully delivered as soon as it writes the event to the program. This means that delivery is not reliable, because if the pipe command crashes events may be lost. |
exit_status |
GreenArrow will wait for a successful exit of the program (exit status 0) before considering an event to be successfully delivered. Other exit statuses will cause the events to be re-written to the next invocation of the pipe command. The pipe command should exit 0 after reading an EOF from STDIN and sucesfully processing all of the events it read from STDIN. Also see event_delivery_pipe_batch_duration. |
event_delivery_destination pipe {
event_delivery_pipe_command /root/deliver_events
event_delivery_pipe_batch_duration 5s
event_delivery_pipe_ack_mode exit_status
}
CSV
This directive is required when using event_delivery_format csv
. There is no
default list of fields that will be written in CSV format, so you must specify the
fields that you want logged.
See Types of Events to get a list of what fields are available for each kind of event.
Additionally, the following fields are available:
time_written_to_logfile |
The time this log message was written to the logfile. Affected by the directive event_delivery_csv_timestamp_format. |
header.XXX |
Any logged header from the original message can be included in the CSV output of
|
"" |
A blank string. This puts a blank field into your CSV output. This can be useful when integrating with existing software that expects a certain number of fields to be present. |
event_delivery_destination logfile {
event_delivery_logfile /root/greenarrow.log
event_delivery_events delivery_attempt
event_delivery_format csv
event_delivery_csv_fields event_time, injected_time, email, status, message, header.X-Info
}
This directive is available when using event_delivery_format csv
.
By default, timestamp fields (e.g. time_written_to_logfile
, injected_time
, event_time
)
will be written as UNIX timestamps. This option allows you to pick an alternative timestamp format.
unix |
Timestamps will be formatted as the number of seconds that have elapsed since Example: |
iso8601 |
Timestamps will be formatted according to ISO 8601 in the time zone configured by engine_time_zone. Example: |
local |
Timestamps will be formatted as Example: |
utc |
Timestamps will be formatted as Example: |
event_delivery_destination logfile {
event_delivery_logfile /root/greenarrow.log
event_delivery_events delivery_attempt
event_delivery_format csv
event_delivery_csv_fields event_time, injected_time, email, status, message
event_delivery_csv_timestamp_format iso8601
}
This directive is available when using event_delivery_format csv
.
This directive is only available for destinations that use event_delivery_logfile.
This directive will cause the first line of new CSV files to be the list of fields that will follow.
event_delivery_destination logfile {
event_delivery_logfile /root/greenarrow.log
event_delivery_events delivery_attempt
event_delivery_format csv
event_delivery_csv_fields event_time, injected_time, email, status, message
event_delivery_csv_write_headers yes
}
This directive is available when using event_delivery_format csv
.
This directive determines how lines will be ended in CSV format.
lf |
Lines will be ended with a single line-feed (ASCII byte 10). |
crlf |
Lines will be ended with both a carriage-return and a line-feed (ASCII byte 13 followed by ASCII byte 10). |
event_delivery_destination logfile {
event_delivery_logfile /root/greenarrow.log
event_delivery_events delivery_attempt
event_delivery_format csv
event_delivery_csv_fields event_time, injected_time, email, status, message
event_delivery_csv_line_terminator crlf
}
SQL Database
Specify that this event_delivery_destination should deliver to a SQL database server (as opposed to an HTTP endpoint or a logfile). This directive specifies the DSN of the target database.
MySQL |
|
MySQL
with tls |
|
PostgreSQL |
|
PostgreSQL
with tls |
|
MS-SQL |
|
SQLite |
|
This cannot be combined with event_delivery_url or its associated directives (nor event_delivery_logfile or its associated directives) on a single event_delivery_destination (however you may certainly have multiple destinations with different delivery mechanisms).
The following directives are available to configure how SQL database delivery is accomplished:
- event_delivery_sql_username (optional, can be included in the DSN)
- event_delivery_sql_password (optional, can be included in the DSN)
- event_delivery_sql_commit_size
- event_delivery_sql_concurrency
- event_delivery_sql_event
- event_delivery_sql_query
- event_delivery_sql_binds
The following directives are more general directives that equally apply to SQL database destinations:
- event_delivery_events
- event_delivery_delivery_attempt_config
- event_delivery_exclude_delivery_attempts_to_mx_hostname
- event_delivery_anonymize_localparts
- event_anonymization_constant
- event_delivery_timeout
After configuring a destination, you can use the command greenarrow events
test_sql_connection DESTINATION
to verify the connection to the remote
database. This command establishes a connection to the server and executes
SELECT 1
to verify operation (i.e. this does not test that your
event_delivery_sql_query nor event_delivery_sql_binds are
correct).
$ greenarrow events test_sql_connection dest-sql
Connection to destination 'dest-sql' verified!
event_delivery_destination destination-sql-server {
event_delivery_events engine_click
event_delivery_sql_dsn dbi:Pg:dbname=greenarrow;host=127.0.0.1
event_delivery_sql_username greenarrow
event_delivery_sql_password my-secret-password
event_delivery_sql_event * {
event_delivery_sql_query "INSERT INTO events_archive ( id, event_unique_id, event_type, event_time, server_id, email, sendid, listid, list_name, list_label, bounce_type, bounce_code, bounce_text, click_url, click_tracking_id, studio_mailing_list_id, studio_subscriber_id, studio_campaign_id, studio_autoresponder_id, studio_is_unique, studio_ip, studio_rl_seq, studio_rl_recipid, studio_rl_seq_id, studio_rl_distinct_id, engine_ip, user_agent, json_before, json_after, timestamp, channel, status, is_retry, msguid, sender, mtaid, mtaid_id, mtaid_name, injected_time, message, outmtaid, outmtaid_name, outmtaid_ip, outmtaid_hostname, sendsliceid, throttleid, mx_hostname, mx_ip, synchronous, from_address, headers, is_privacy_open, message_size, smtp_timing, report_recipient, report_message_text, report_sender, bounce_code_match_text, source_ip, linkid, mailclass, instanceid ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) ON CONFLICT DO NOTHING"
event_delivery_sql_binds id, event_unique_id, event_type, event_time, server_id, email, sendid, listid, list_name, list_label, bounce_type, bounce_code, bounce_text, click_url, click_tracking_id, studio_mailing_list_id, studio_subscriber_id, studio_campaign_id, studio_autoresponder_id, studio_is_unique, studio_ip, studio_rl_seq, studio_rl_recipid, studio_rl_seq_id, studio_rl_distinct_id, engine_ip, user_agent, json_before, json_after, timestamp, channel, status, is_retry, msguid, sender, mtaid, mtaid_id, mtaid_name, injected_time, message, outmtaid, outmtaid_name, outmtaid_ip, outmtaid_hostname, sendsliceid, throttleid, mx_hostname, mx_ip, synchronous, from_address, headers, is_privacy_open, message_size, smtp_timing, report_recipient, report_message_text, report_sender, bounce_code_match_text, source_ip, linkid, mailclass, instanceid
}
}
Specify the username that should be used for authentication with this SQL server. This directive is optional and the username may be embedded into event_delivery_sql_dsn.
event_delivery_destination destination-sql-server {
event_delivery_sql_dsn dbi:Pg:dbname=greenarrow;host=127.0.0.1
event_delivery_sql_username greenarrow
}
Specify the password that should be used for authentication with this SQL server. This directive is optional and the username may be embedded into event_delivery_sql_dsn.
event_delivery_destination destination-sql-server {
event_delivery_sql_dsn dbi:Pg:dbname=greenarrow;host=127.0.0.1
event_delivery_sql_username greenarrow
event_delivery_sql_password my-secret-password
}
Specify the maximum number of events that should be written to the remote database as part of each commit.
event_delivery_destination destination-sql-server {
event_delivery_sql_dsn dbi:Pg:dbname=greenarrow;host=127.0.0.1
event_delivery_sql_commit_size 10
}
Specify how many concurrent connections to the configured SQL database server this destination should establish. Higher values will tend to increase throughput.
event_delivery_destination destination-sql-server {
event_delivery_sql_dsn dbi:Pg:dbname=greenarrow;host=127.0.0.1
event_delivery_sql_concurrency 50
}
This grouping context is to define the particular SQL query and column binds to use for the listed event types.
Refer to the event_delivery_events directive for a full list of available events.
Specifying an event type of *
will act as the default for any non-specified
event types.
event_delivery_destination destination-sql-server {
event_delivery_events all
event_delivery_sql_dsn dbi:Pg:dbname=greenarrow;host=127.0.0.1
event_delivery_sql_event engine_open, studio_open {
event_delivery_sql_query "INSERT INTO opens_archive ( id, event_type ) VALUES ( ?, ? ) ON CONFLICT DO NOTHING"
event_delivery_sql_binds id, event_type
}
event_delivery_sql_event * {
event_delivery_sql_query "INSERT INTO events_archive ( id, event_type ) VALUES ( ?, ? ) ON CONFLICT DO NOTHING"
event_delivery_sql_binds id, event_type
}
}
The SQL query that should be executed for each matching event.
event_delivery_destination destination-sql-server {
event_delivery_events all
event_delivery_sql_dsn dbi:Pg:dbname=greenarrow;host=127.0.0.1
event_delivery_sql_event * {
event_delivery_sql_query "INSERT INTO events_archive ( id, event_unique_id, event_type, event_time, server_id, email, sendid, listid, list_name, list_label, bounce_type, bounce_code, bounce_text, click_url, click_tracking_id, studio_mailing_list_id, studio_subscriber_id, studio_campaign_id, studio_autoresponder_id, studio_is_unique, studio_ip, studio_rl_seq, studio_rl_recipid, studio_rl_seq_id, studio_rl_distinct_id, engine_ip, user_agent, json_before, json_after, timestamp, channel, status, is_retry, msguid, sender, mtaid, mtaid_id, mtaid_name, injected_time, message, outmtaid, outmtaid_name, outmtaid_ip, outmtaid_hostname, sendsliceid, throttleid, mx_hostname, mx_ip, synchronous, from_address, headers, is_privacy_open, message_size, smtp_timing, report_recipient, report_message_text, report_sender, bounce_code_match_text, source_ip, linkid, mailclass, instanceid ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) ON CONFLICT DO NOTHING"
event_delivery_sql_binds id, event_unique_id, event_type, event_time, server_id, email, sendid, listid, list_name, list_label, bounce_type, bounce_code, bounce_text, click_url, click_tracking_id, studio_mailing_list_id, studio_subscriber_id, studio_campaign_id, studio_autoresponder_id, studio_is_unique, studio_ip, studio_rl_seq, studio_rl_recipid, studio_rl_seq_id, studio_rl_distinct_id, engine_ip, user_agent, json_before, json_after, timestamp, channel, status, is_retry, msguid, sender, mtaid, mtaid_id, mtaid_name, injected_time, message, outmtaid, outmtaid_name, outmtaid_ip, outmtaid_hostname, sendsliceid, throttleid, mx_hostname, mx_ip, synchronous, from_address, headers, is_privacy_open, message_size, smtp_timing, report_recipient, report_message_text, report_sender, bounce_code_match_text, source_ip, linkid, mailclass, instanceid
}
}
The list of columns that should be bound to the SQL query specified in event_delivery_sql_query.
Valid columns include:
id
event_unique_id
event_type
event_time
server_id
email
sendid
listid
list_name
list_label
bounce_type
bounce_code
bounce_text
click_url
click_tracking_id
studio_mailing_list_id
studio_subscriber_id
studio_campaign_id
studio_autoresponder_id
studio_is_unique
studio_ip
studio_rl_seq
studio_rl_recipid
studio_rl_seq_id
studio_rl_distinct_id
engine_ip
user_agent
json_before
json_after
timestamp
channel
status
is_retry
msguid
sender
mtaid
mtaid_id
mtaid_name
injected_time
message
outmtaid
outmtaid_name
outmtaid_ip
outmtaid_hostname
sendsliceid
throttleid
mx_hostname
mx_ip
synchronous
from_address
headers
is_privacy_open
message_size
smtp_timing
report_recipient
report_message_text
report_sender
bounce_code_match_text
source_ip
linkid
mailclass
instanceid
event_delivery_destination destination-sql-server {
event_delivery_events all
event_delivery_sql_dsn dbi:Pg:dbname=greenarrow;host=127.0.0.1
event_delivery_sql_event * {
event_delivery_sql_query "INSERT INTO events_archive ( id, event_unique_id, event_type, event_time, server_id, email, sendid, listid, list_name, list_label, bounce_type, bounce_code, bounce_text, click_url, click_tracking_id, studio_mailing_list_id, studio_subscriber_id, studio_campaign_id, studio_autoresponder_id, studio_is_unique, studio_ip, studio_rl_seq, studio_rl_recipid, studio_rl_seq_id, studio_rl_distinct_id, engine_ip, user_agent, json_before, json_after, timestamp, channel, status, is_retry, msguid, sender, mtaid, mtaid_id, mtaid_name, injected_time, message, outmtaid, outmtaid_name, outmtaid_ip, outmtaid_hostname, sendsliceid, throttleid, mx_hostname, mx_ip, synchronous, from_address, headers, is_privacy_open, message_size, smtp_timing, report_recipient, report_message_text, report_sender, bounce_code_match_text, source_ip, linkid, mailclass, instanceid ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) ON CONFLICT DO NOTHING"
event_delivery_sql_binds id, event_unique_id, event_type, event_time, server_id, email, sendid, listid, list_name, list_label, bounce_type, bounce_code, bounce_text, click_url, click_tracking_id, studio_mailing_list_id, studio_subscriber_id, studio_campaign_id, studio_autoresponder_id, studio_is_unique, studio_ip, studio_rl_seq, studio_rl_recipid, studio_rl_seq_id, studio_rl_distinct_id, engine_ip, user_agent, json_before, json_after, timestamp, channel, status, is_retry, msguid, sender, mtaid, mtaid_id, mtaid_name, injected_time, message, outmtaid, outmtaid_name, outmtaid_ip, outmtaid_hostname, sendsliceid, throttleid, mx_hostname, mx_ip, synchronous, from_address, headers, is_privacy_open, message_size, smtp_timing, report_recipient, report_message_text, report_sender, bounce_code_match_text, source_ip, linkid, mailclass, instanceid
}
}
Syntax Checker
To check if your configuration file is valid without applying its settings, run the following.
# greenarrow_config validate
No errors found. Configuration file is acceptable.
This command will let you know that the syntax of your configuration file is correct and warn you of any unknown directives.
Reload Configuration in Active Services
Anytime a service starts up, it will use whatever configuration is currently in
/var/hvmail/control/greenarrow.conf
. If the configuration cannot be
successfully loaded, the service will not start. See the Detecting and
Correcting Invalid Configuration section below
for more information on troubleshooting an invalid configuration file.
To apply an update to the configuration file, there are reload commands listed below. Combined, these commands apply all of the configurations in the configuration file.
Update the configuration running on services that do not require restarts
This command will load the new configuration into services that do not require restarts or result in downtime.
This applies most directives in the configuration file. If a directive is not
applied by this reload
command, it will say so explicitly in the directive’s
documentation.
greenarrow_config reload
Update Passenger’s configuration
This command will reload Passenger with the new configuration. This results in a delay (15-60 seconds depending on server speed) of servicing web requests.
greenarrow_config reload_passenger
Running this command without the --force
argument will require confirmation
by typing y
when asked.
Update PostgreSQL’s configuration
This command will reload PostgreSQL with the new configuration. This is considered a HIGH IMPACT operation and will severely disrupt all running services. This operation typically takes 60 seconds.
greenarrow_config reload_postgres
Running this command without the --force
argument will require confirmation
by typing y
when asked.
Update SimpleMH’s configuration
This command will reload SimpleMH with the new configuration. This can result in less than a second of new messages getting temporary errors on injection.
greenarrow_config reload_simplemh
Running this command without the --force
argument will require confirmation
by typing y
when asked.
Detecting and Correcting Invalid Configuration
If a service cannot start due to an invalid greenarrow.conf
, this is how you
can diagnose the problem.
Run hvmail_init status
. When the configuration file is invalid, it will say
so at the top of the output.
# hvmail_init status
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Errors found in configuration file (/var/hvmail/control/greenarrow.conf):
- line 26: unknown identifier invalid_grouping_directive
This will prevent multiple services from being able to start or restart.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
QUEUE SERVICE STARTED OK FILE EXISTS RAMDISK ACTIVE
ram yes yes yes
bounce yes yes yes
disk yes yes n/a
LICENSE: current
SERVICES:
Name Primary Service Status Log Service Status
hvmail-bounce-processor UP UP
hvmail-bounce-processor2 UP UP
hvmail-bounce-qmail-send UP UP
hvmail-config-agent UP UP
hvmail-dd-dispatcher UP UP
hvmail-dd-logreader UP UP
hvmail-disk-qmail-send UP UP
hvmail-dnscache DOWN
hvmail-event-processor UP UP
hvmail-event-processor2 UP UP
hvmail-httpd UP UP
hvmail-httpd-monitor UP UP
hvmail-logfile-agent UP UP
hvmail-logfile-summary UP UP
hvmail-logfile-writer UP UP
hvmail-passenger UP UP
hvmail-postgres UP UP
hvmail-pure-authd-studio UP UP
hvmail-pure-ftpd UP UP
hvmail-qmail-pop3d UP UP
hvmail-qmail-smtpd UP UP
hvmail-qmail-smtpd2 UP UP
hvmail-qmail-smtpd3 DOWN
hvmail-ram-qmail-send UP UP
hvmail-redis UP UP
hvmail-redis-np UP UP
hvmail-rpc UP UP
hvmail-rspawn-limiter UP UP
hvmail-simplemh UP UP
hvmail-simplemh2 UP UP
hvmail-smtp-sink UP UP
hvmail-studio-worker UP UP
hvmail-tls UP UP
OVERALL STATUS: UP
In the example above, you’ll see the warning banner at the top of the output.
Additionally, the hvmail-httpd
service is stuck at a state of STARTING
. If
you look into the log files, you’ll see the error there as well.
# tail /var/hvmail/log/httpd/current | tai64nlocal
2018-04-13 08:10:58.148551500 error (256) while loading greenarrow configuration
2018-04-13 08:10:58.148922500 ERROR: failed to generate configuration
2018-04-13 08:10:59.159582500 /var/hvmail/bin/greenarrow_config: Errors found in configuration file (/var/hvmail/control/greenarrow.conf):
2018-04-13 08:10:59.159584500 - line 26: unknown identifier invalid_grouping_directive
2018-04-13 08:10:59.161435500 error (256) while loading greenarrow configuration
2018-04-13 08:10:59.161436500 ERROR: failed to generate configuration
2018-04-13 08:11:00.182314500 /var/hvmail/bin/greenarrow_config: Errors found in configuration file (/var/hvmail/control/greenarrow.conf):
2018-04-13 08:11:00.182317500 - line 26: unknown identifier invalid_grouping_directive
2018-04-13 08:11:00.183340500 error (256) while loading greenarrow configuration
2018-04-13 08:11:00.184608500 ERROR: failed to generate configuration
The error output should give you enough information to fix the problem in
greenarrow.conf
. Once the problem has been corrected, the service will
automatically start up and resume normal operation.
Dynamic Defaults
Some of GreenArrow’s settings default to being adjusted automatically based upon the available CPU and RAM resources.
To view the values used for these fields, run the following command.
# greenarrow_config show_dynamic_defaults
Directive Default Override
--------------------------------------------------------------------------------------------------
general.studio_message_generation_processes_per_campaign 2 2
general.studio_workers_shared 0 -
general.studio_workers_campaigns 10 15
general.studio_workers_general 2 -
general.studio_workers_imports 1 -
general.studio_workers_transactional 1 -
general.passenger_max_requests_in_queue 768 -
general.passenger_min_application_instances 16 -
general.passenger_max_application_instances 16 -
general.apache_max_clients 1024 -
general.postgres_max_connections 300 -
Estimated memory requirements Default As Configured
--------------------------------------------------------------------------------------------------
Passenger web processes 3200 MB 3200 MB
Studio worker processes (/service/hvmail-studio-worker) 2400 MB 3400 MB
--------------------------------------------------------------------------------------------------
The memory estimates listed above do not reflect all components within GreenArrow, but only
these specific components. See the documentation on Memory Utilization for more information:
https://www.greenarrowemail.com/docs/greenarrow-engine/Configuration/Performance-Tuning/Memory-Utilization
If you would like to “freeze” those values so they no longer dynamically adjust, run the following command.
greenarrow_config freeze_dynamic_defaults >> /var/hvmail/control/greenarrow.conf
If running the above command results in duplicate configuration entries, then the last of the duplicates takes precedence.
See the documentation on Memory Utilization for more information.
Review Per-Domain Configuration
The command greenarrow_config domain_settings
is a diagnostic tool used to
see, with the current configuration in /var/hvmail/control/greenarrow.conf
,
what settings apply to a specific IP/Domain combination.
For example, given this configuration:
ip_address * {
domain * {
reuse_connections yes
reuse_connections_timeout 2s
reuse_connections_max_messages 100
log_smtp_commands yes
}
domain yahoo.com {
log_smtp_hexdump yes
}
}
ip_address smtp-1 {
domain * {
reuse_connections_max_messages 500
}
domain gmail.com {
reuse_connections_max_messages 2500
starttls_use yes
}
}
Here are some example invocations:
# greenarrow_config domain_settings smtp-1 gmail.com
Configuration on IP "smtp-1" to domain "gmail.com":
------------------------------------------------------------------------
reuse_connections | true
reuse_connections_timeout | 2s
reuse_connections_max_messages | 2500
starttls_use | true
starttls_require | <default>
starttls_require_action | <default>
delivery_override | <default>
smtp_route | <default>
message_transfer_timeout_action | <default>
message_transfer_response_timeout_action | <default>
log_dns | <default>
log_smtp_connections | <default>
log_smtp_commands | true
log_smtp_hexdump | <default>
max_concurrent_connections | <default>
max_delivery_rate | <default>
throttle_program | <default>
# greenarrow_config domain_settings smtp-1 yahoo.com
Configuration on IP "smtp-1" to domain "yahoo.com":
------------------------------------------------------------------------
reuse_connections | true
reuse_connections_timeout | 2s
reuse_connections_max_messages | 500
starttls_use | <default>
starttls_require | <default>
starttls_require_action | <default>
delivery_override | <default>
smtp_route | <default>
message_transfer_timeout_action | <default>
message_transfer_response_timeout_action | <default>
log_dns | <default>
log_smtp_connections | <default>
log_smtp_commands | true
log_smtp_hexdump | true
max_concurrent_connections | <default>
max_delivery_rate | <default>
throttle_program | <default>
# greenarrow_config domain_settings smtp-2 gmail.com
Configuration on IP "smtp-2" to domain "gmail.com":
------------------------------------------------------------------------
reuse_connections | true
reuse_connections_timeout | 2s
reuse_connections_max_messages | 100
starttls_use | <default>
starttls_require | <default>
starttls_require_action | <default>
delivery_override | <default>
smtp_route | <default>
message_transfer_timeout_action | <default>
message_transfer_response_timeout_action | <default>
log_dns | <default>
log_smtp_connections | <default>
log_smtp_commands | true
log_smtp_hexdump | <default>
max_concurrent_connections | <default>
max_delivery_rate | <default>
throttle_program | <default>
# greenarrow_config domain_settings smtp-2 yahoo.com
Configuration on IP "smtp-2" to domain "yahoo.com":
------------------------------------------------------------------------
reuse_connections | true
reuse_connections_timeout | 2s
reuse_connections_max_messages | 100
starttls_use | <default>
starttls_require | <default>
starttls_require_action | <default>
delivery_override | <default>
smtp_route | <default>
message_transfer_timeout_action | <default>
message_transfer_response_timeout_action | <default>
log_dns | <default>
log_smtp_connections | <default>
log_smtp_commands | true
log_smtp_hexdump | true
max_concurrent_connections | <default>
max_delivery_rate | <default>
throttle_program | <default>
Example File
Here is an example file:
general {
studio_message_generation_processes_per_campaign 1
studio_workers_shared 5
studio_workers_campaigns 0
studio_workers_general 3
studio_workers_imports 0
studio_workers_transactional 1
passenger_max_requests_in_queue 256
passenger_min_application_instances 2
passenger_max_application_instances 4
apache_max_clients 500
postgres_max_connections 200
}