GreenArrow Email Software Documentation

Configuration 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 (;), and percentages (%) 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.

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

GreenArrow uses Go’s regular expression engine documented here.

Boolean Encoding

Booleans may be specified as yes or no.

Duration Encoding

A time interval 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, and h.

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.

Grouping Contexts

The greenarrow.conf configuration file is organized hierarchically as described below:

syntax:
general { other_directives }
context:
top-level

This top-level group contains settings that do not belong in any other group.

syntax:
ip_address ip_address_name [, ... ] { other_directives }
context:
top-level

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 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** {
  ...
}

syntax:
relay_server relay_server_name [, ... ] { other_directives }
context:
top-level

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.

syntax:
domain domain_name [, ... ] { other_directives }
context:

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 matches example.com, subdomain.example.com, and www.subdomain.example.com.
  • A domain that is prefixed with *. matches only subdomains. For example, *.example.com matches subdomain.example.com and www.subdomain.example.com, but will not match example.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:

  1. The **super** IP record, exact recipient domain.
  2. The **super** IP record, wildcard recipient domain.
  3. The **super** IP record, exact match of MX domain (mx:mx1.example.com).
  4. The **super** IP record, wildcard match of MX domain.
  5. The **super** IP record, match of an MX IP address (a:1.2.3.4).
  6. The **super** IP record, wildcard domain (*).
  7. An exact IP name match, exact match of recipient domain.
  8. An exact IP name match, wildcard match of recipient domain.
  9. An exact IP name match, exact match of MX domain.
  10. An exact IP name match, wildcard match of MX domain.
  11. An exact IP name match, wildcard domain (*).
  12. The * IP record, exact match of recipient domain.
  13. The * IP record, wildcard match of recipient domain.
  14. The * IP record, exact match of MX domain.
  15. The * IP record, wildcard match of MX domain.
  16. 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 * {
    ...
  }
}

syntax:
routing_rule name [, ... ] { other_directives }
context:
top-level

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 {
  ...
}

syntax:
routing_rule_domain domain_name [, ... ] { other_directives }
context:

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
  }
  ...
}

syntax:
virtual_mta_injected name [, ... ] { other_directives }
context:
top-level

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 through ip_a and ip_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.
  • virtual_mta_injected "*" { }
    • This is the default and, unless overridden by a more precise directive, applies to all messages.
  • virtual_mta "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, not ip_a.
  • virtual_mta "shared_pool" { }
    • The message was delivered on ip_a, not shared_pool.

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 {
  ...
}

syntax:
database_connection name { other_directives }
context:
top-level

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 {
  ...
}

syntax:
dkim_domain domain_name [, ... ] { other_directives }
context:
top-level

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"
  ...
}

syntax:
url_domain domain_name [, ... ] { other_directives }
context:
top-level

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
}

syntax:
incoming_email_domain domain_name [, ... ] { other_directives }
context:
top-level

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
  ...
}

syntax:
user_mailbox localpart [, ... ] { other_directives }

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
    ...
  }
}

syntax:
forwarding_mailbox localpart [, ... ] { other_directives }

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]"
    ...
  }
}

syntax:
throttle_program name [, ... ] { other_directives }
context:
top-level

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%
  ....
}

syntax:
mail_class name [, ... ] { other_directives }
context:
top-level

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.

mail_class orders {
  virtual_mta smtp1
  ....
}

Configuration Directives

Directives are configuration settings that apply a specific option within a context.

syntax:
domain_macro macro_name domain1, domain2 [, ... ]
context:
top-level

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.

syntax:
include filename
context:
top-level

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 only be specified at the top-level of a file.

include /usr/local/etc/ga/ip_addresses.conf
include /usr/local/etc/ga/general.conf

Performance Tuning

GreenArrow Studio

The settings in this section pertain to GreenArrow Studio.

syntax:
studio_message_generation_processes_per_campaign integer
default:
Automatic based upon the available CPU/RAM resources.
context:

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
}

syntax:
studio_workers_shared integer
default:
Automatic based upon the available CPU/RAM resources.
context:

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
}

syntax:
studio_workers_campaigns integer
default:
Automatic based upon the available CPU/RAM resources.
context:

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
}

syntax:
studio_workers_general integer
default:
Automatic based upon the available CPU/RAM resources.
context:

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
}

syntax:
studio_workers_imports integer
default:
Automatic based upon the available CPU/RAM resources.
context:

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
}

syntax:
studio_workers_transactional integer
default:
Automatic based upon the available CPU/RAM resources.
context:

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.

syntax:
passenger_max_requests_in_queue integer
default:
Automatic based upon the available CPU/RAM resources.
context:

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
}

syntax:
passenger_min_application_instances integer
default:
Automatic based upon the available CPU/RAM resources.
context:

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
}

syntax:
passenger_max_application_instances integer
default:
Automatic based upon the available CPU/RAM resources.
context:

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
}

syntax:
apache_max_clients integer
default:
Automatic based upon the available CPU/RAM resources.
context:

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

syntax:
write_could_not_process_bounce_messages boolean
default:
yes
context:

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
}

syntax:
bounce_processor_rule regexp code [options]
context:

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.

Optional arguments:

case_insensitive

boolean

/

default: no

Match the regular expression case insensitively.

pre_lowercase

boolean

/

default: no

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: yes

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
}

Database Server

syntax:
postgres_max_connections integer
default:
Automatic based upon the available CPU/RAM resources.
context:

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 +
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.

syntax:
system_memory_gigabytes float
default:
The amount of RAM in the system, in gigabytes.
context:

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
}

syntax:
system_cpu_core_count integer
default:
The number of CPU cores in the system.
context:

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

syntax:
simplemh_max_servers integer
default:
50
context:

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
}

syntax:
simplemh_min_servers integer
default:
5
context:

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
}

syntax:
simplemh_max_spare_servers integer
default:
10
context:

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
}

syntax:
simplemh_min_spare_servers integer
default:
2
context:

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
}

syntax:
simplemh_max_server_requests integer
default:
20000
context:

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
}

Event Processor

syntax:
disable_automatic_shrink_events_table boolean
default:
no
context:

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.

syntax:
disk_queue_writer_batch_max_messages integer
default:
10
context:

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
}

syntax:
disk_queue_writer_batch_max_time duration
default:
10s
context:

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
}

syntax:
disk_queue_writer_concurrency integer
default:
20
context:

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
}

syntax:
disk_queue_writer_fsync boolean
default:
yes
context:

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

syntax:
max_dns_queries integer
default:
100
context:

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

syntax:
notify_on_backoff email_address [, ... ]
default:
none
context:

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 [email protected], 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

syntax:
smtp_match_begin_backoff_mode regexp [options]
context:

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”).

Matching will be done based on the order defined in the domain directive. If two smtp_match_begin_backoff_mode directives of the same precedence match an SMTP response, the first one defined in the configuration file will take priority.

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 success, perm_failure, or temp_failure).

case_insensitive

boolean

/

default: no

Match the regular expression case insensitively.

pre_lowercase

boolean

/

default: no

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: logfile



Match on the specified response format. Valid formats are listed below. See this page for a discussion on the differences between these formats.

raw

The raw SMTP response instead of a GreenArrow format. Only messages that actually come from a remote host can be matched using this format. For example, delivery_override messages are created within GreenArrow, so the “raw” format is blank.

logfile

The GreenArrow raw logfile format. This is the most common format to observe of delivery attempt messages in GreenArrow and is therefore the default.

processed

The GreenArrow processed logfile format.

web

The format shown in GreenArrow’s web user interface and stats API.

default_duration

time duration

/

default: 15m

The default time duration to run in backoff mode if no Throttle Program is configured for this throttle.

duration

time 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 default_duration and any configured throttle program.

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
  }
}

Outgoing Connections

syntax:
system_max_smtp_connections integer
default:
10000
context:

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
}

syntax:
reuse_connections boolean
default:
no
context:
domain (within ip_address)

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
  }
}

syntax:
reuse_connections_timeout time duration
default:
1s
context:
domain (within ip_address)

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
  }
}

syntax:
reuse_connections_max_messages integer
default:
100
context:
domain (within ip_address)

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
  }
}

syntax:
queue_lifetime time duration
default:
2d
context:

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
  }
}

syntax:
retry_time time duration, ...
context:

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
  }
}

Encryption

syntax:
starttls_use boolean
default:
no
context:
domain (within ip_address)

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
  }
}

syntax:
starttls_require boolean
default:
no
context:
domain (within ip_address)

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
  }
}

syntax:
starttls_require_action string
default:
perm_fail
context:
domain (within ip_address)

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:

Connected to {IP} but STARTTLS is not available, delivery attempt not made. (#5.7.10)

temp_failure

A temporary failure is returned and the message may be retried.

The following message is returned:

Connected to {IP} but STARTTLS is not available, delivery attempt not made. (#4.7.10)

discard

A fake “success” is generated to prevent the message from being retried.

The following message is returned:

Connected to {IP} but STARTTLS is not available, delivery attempt not made. (#2.7.10)

# 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

syntax:
delivery_paused boolean
default:
no
context:

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
}

syntax:
delivery_override mode message
default:
none
context:
domain (within ip_address)

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:

Delivery attempt prevented by local configuration. (#5.7.1)

temp_failure

No delivery attempt occurs; instead, a fake temporary failure (deferral) is returned:

Delivery attempt prevented by local configuration. (#4.7.1)

discard

No delivery attempt occurs; instead, a fake acceptance is returned:

This message was discarded by local configuration. (#2.7.1)

# 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"
  }
}

syntax:
smtp_route string
default:
none
context:

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
  }
}

syntax:
override_smtp_result regexp new_result [options]
context:

This directive allows you to override the SMTP result (either success, perm_failure, or temp_failure) based upon a regular expression matching the SMTP response.

Optional arguments:

smtp_result

string

Only override if the original SMTP result was this (either success, perm_failure, or temp_failure).

case_insensitive

boolean

/

default: no

Match the regular expression case insensitively.

pre_lowercase

boolean

/

default: no

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: logfile



Match on the specified response format. Valid formats are listed below. See this page for a discussion on the differences between these formats.

raw

The raw SMTP response instead of a GreenArrow format. Only messages that actually come from a remote host can be matched using this format. For example, delivery_override messages are created within GreenArrow, so the “raw” format is blank.

logfile

The GreenArrow raw logfile format. This is the most common format to observe of delivery attempt messages in GreenArrow and is therefore the default.

processed

The GreenArrow processed logfile format.

web

The format shown in GreenArrow’s web user interface and stats API.

ip_address * {
  domain * {
    override_smtp_result /over quota/ success case_insensitive=yes
  }
}

Error Handling

syntax:
message_transfer_timeout_action string
default:
temp_failure
context:
domain (within ip_address)

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:

Connected to {IP} but connection died. (#5.4.2)

temp_failure

A temporary failure is returned and the message may be retried.

The following message is returned:

Connected to {IP} but connection died. (#4.4.2)

discard

A fake “success” is generated to prevent the message from being retried.

The following message is returned:

Connected to {IP} but connection died. (#2.4.2)

ip_address * {
  # Message transfer timeouts shouldn't be retried.
  domain yahoo.com {
    message_transfer_timeout_action perm_failure
  }
}

syntax:
message_transfer_response_timeout_action string
default:
temp_failure
context:
domain (within ip_address)

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:

Connected to {IP} but connection died. Possible duplicate! (#5.4.2)

temp_failure

A temporary failure is returned and the message may be retried.

The following message is returned:

Connected to {IP} but connection died. Possible duplicate! (#4.4.2)

discard

A fake “success” is generated to prevent the message from being retried.

The following message is returned:

Connected to {IP} but connection died. Possible duplicate! (#2.4.2)

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.

syntax:
pcompat_dkim_key selector domain private_key_filename
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, then a DKIM key matching one of these domain names is searched for. The first match is used:

  • The domain name specified in a Sender header, if present
  • The domain name specified in the From header

If there IS a pcompat_dkim_identity value defined, then a DKIM key matching this domain name is searched for:

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.

virtual_mta_injected ipaddr-1 {
  pcompat_dkim_key selector example.com /path/to/private_key_filename.pem
}

syntax:
pcompat_dkim_sign boolean
default:
no

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.

Caveat - The GreenArrow PowerMTA compatibility DKIM signing system signs messages at the time of injection. It appears that PowerMTA signs messages at the time of delivery.

virtual_mta_injected * {
  pcompat_dkim_sign yes
}

syntax:
pcompat_dkim_identity domain

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.

For a description of how this is used, see the documentation of the pcompat_dkim_key directive.

virtual_mta_injected * {
  pcompat_dkim_identity example.com
}

syntax:
dkim_sign_ignore_header header1, header2, ...
default:
none
context:

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"
}

syntax:
dkim_sign_canonicalization_mode simple|relaxed
default:
relaxed
context:

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

syntax:
replace_content_domain domain.com
default:
none

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
}

syntax:
replace_content_domain_applies_to_from_domain boolean
default:
false

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
}

syntax:
replace_content_domain_applies_to_reply_to_domain boolean
default:
false

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
}

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

syntax:
disk_queue_log_debug crash|always|never
default:
crash
context:

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 /var/hvmail/var/tmp/greenarrow_dump*), but not the normal disk queue log.

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

syntax:
log_dns boolean
default:
no
context:
domain (within ip_address)

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

syntax:
log_smtp_connections boolean
default:
no
context:
domain (within ip_address)

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
  }
}

syntax:
log_smtp_commands boolean
default:
no
context:
domain (within ip_address)

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
  }
}

syntax:
log_smtp_hexdump boolean
default:
no
context:
domain (within ip_address)

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:<[email protected]|
(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
  }
}

syntax:
log_header header1, header2, ...
context:

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"
}

VirtualMTAs

syntax:
define_virtual_mtas_in_config_file boolean
default:
no
context:

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
}

syntax:
default_virtual_mta string
context:

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
}

syntax:
smtp_source_hostname string

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
}

syntax:
smtp_source_ip string

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
}

syntax:
smtp_auth username password
context:

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
}

syntax:
max_concurrent_connections integer
default:
no limit
context:

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
  }
}

syntax:
max_delivery_rate rate
default:
no limit

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
  }
}

syntax:
throttle_program string
context:

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.

syntax:
proxy_server hostname or ip { other_directives }
context:

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.

syntax:
proxy_server_local_bind ip
context:

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
  }
}

syntax:
routing_rule_destination virtual_mta [percentage]

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.

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
  }
}

syntax:
randomization_type type

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
  }
}

DNS Cache

syntax:
dns_cache_service_run boolean
default:
no
context:

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.

Database Connections

syntax:
define_database_connections_in_config_file boolean
default:
no
context:

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
}

syntax:
database_type string

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
}

syntax:
database_host string

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.

syntax:
database_username string

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
}

syntax:
database_password string

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
}

syntax:
database_name string

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
}

syntax:
is_remote boolean
default:
no

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
}

syntax:
use_ssl boolean
default:
no

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
}

syntax:
extra_dsn_string string

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"
}

syntax:
notes string

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

syntax:
define_dkim_keys_in_config_file boolean
default:
no
context:

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
}

syntax:
dkim_key selector private_key_filename default=boolean
context:
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 dkim_domain directive (the parent domains). Defaults to no.

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

syntax:
url_domains_always_use_tls boolean
default:
yes
context:

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
}

syntax:
url_domains_get_lets_encrypt_certs boolean
default:
yes
context:

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
}

syntax:
define_url_domains_in_config_file boolean
default:
no
context:

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
}

syntax:
use_ssl boolean
default:
no
context:

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

syntax:
define_incoming_email_domains_in_config_file boolean
default:
no
context:

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
}

syntax:
domain_aliases domain_name [, ... ]

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.

syntax:
email_status string
default:
normal

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.

syntax:
bounce_mailbox domain_name [, ... ]

This directive lists the localparts of one or more bounce mailboxes.

syntax:
spam_complaint_mailbox domain_name [, ... ]

This directive lists the localparts of one or more spam complaint mailboxes.

syntax:
mailbox_is_wildcard boolean
default:
no

By default, mailboxes receive mail for [email protected] 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.

syntax:
mailbox_forward_to email_address

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.

syntax:
mailbox_delivery_mode string
context:

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 forward logic and the other using the local logic.

dotqmail

Process incoming email according to the rules in a .qmail file.

syntax:
mailbox_dotqmail string
context:

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.

syntax:
mailbox_password string
context:

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.

syntax:
mailbox_password_encoded string
context:

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
c37f5859.519996598087b0c6798245b7c3415f83ea4bad03d4f4e46791221a486727de7d

$ greenarrow encode_mailbox_password --prompt
Enter password: <enter password first time>
Enter password (confirm): <confirm password>
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 "c37f5859.519996598087b0c6798245b7c3415f83ea4bad03d4f4e46791221a486727de7d"
  }
}

syntax:
mailbox_locked boolean
default:
no
context:

This directive controls whether the mailbox is locked. Locked mailboxes cannot authenticate using POP3 or SMTP, but can still receive mail.

Throttle Programs

syntax:
define_throttle_programs_in_config_file boolean
default:
no
context:

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
}

syntax:
backoff_max_concurrent_connections percentage or integer
context:

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%
}

syntax:
backoff_max_messages_per_hour percentage or integer
context:

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%
}

syntax:
return_after duration
context:

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
}

syntax:
trigger_failure_rate percentage
context:

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%
}

syntax:
trigger_deferral_rate percentage
context:

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%
}

syntax:
trigger_required_attempts integer
context:

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.

syntax:
define_mail_classes_in_config_file boolean
default:
no
context:

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
}

syntax:
bounce_address_external string [, ... ]
context:

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]"
}

syntax:
virtual_mta string
context:

This directive sets the VirtualMTA used by a Mail Class.

mail_class orders {
  virtual_mta smtp1-1
}

syntax:
listid string
context:

This directive sets the ListID used by a Mail Class.

mail_class orders {
  listid widgets
}

syntax:
seed integer integer
default:
disabled
context:

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
}

syntax:
track_clicks_and_opens boolean
default:
no
context:

This directive turns on or off click and open tracking for the Mail Class.

mail_class orders {
  track_clicks_and_opens yes
}

syntax:
manage_unsubscribe_links boolean
default:
no
context:

This directive turns on or off unsubscribe link tracking for the Mail Class.

mail_class orders {
  manage_unsubscribe_links yes
}

syntax:
archive_sample_count integer
default:
disabled
context:

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
}

syntax:
add_message_id_if_missing boolean
default:
no
context:

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
}

syntax:
url_domain string
default:
$CLICKTHROUGH_URL in /var/hvmail/control/simplemh-config
context:

This directive controls the URL Domain to use for click and open tracking.

mail_class orders {
  url_domain ga.example.com
}

syntax:
bounce_address string
default:
$RETURN_PATH_OVERRIDE in /var/hvmail/control/simplemh-config
context:

This directive controls the bounce mailbox to use for messages in this Mail Class. The specified mailbox must be either:

  1. A local bounce mailbox configured via greenarrow.conf, the configuration API, or GreenArrow’s web interface.
  2. Defined in a bounce_address_external directive.

mail_class orders {
  bounce_address "[email protected]"
}

syntax:
convert_textonly_to_html_do_conversion boolean
default:
no
context:

This directive controls whether GreenArrow will convert text only messages to HTML.

mail_class orders {
  convert_textonly_to_html_do_conversion yes
}

syntax:
convert_textonly_to_html_header_to_add string
context:

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=043caf89dbc0eb652ba9398f2eba11eequot;https://example.com/logo.png043caf89dbc0eb652ba9398f2eba11eequot;>"
}

syntax:
convert_textonly_to_html_footer_to_add string
context:

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=7107b688371711ded4638d600c2fec2dquot;https://example.com/footer.png7107b688371711ded4638d600c2fec2dquot;>"
}

syntax:
convert_textonly_to_html_link_text string
context:

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
}

syntax:
modify_html_header string
context:

This directive causes GreenArrow to prepend the specified header to the HTML version of each message.

mail_class orders {
  modify_html_header "<img src=935e6d3efe9f5875c52e6545f3021a8cquot;https://example.com/logo.png935e6d3efe9f5875c52e6545f3021a8cquot;>"
}

syntax:
modify_html_footer string
context:

This directive causes GreenArrow to append the specified footer to the HTML version of each message.

mail_class orders {
  modify_html_footer "<img src=cd9b9365f08c968b7530d7e41a8d9761quot;https://example.com/footer.pngcd9b9365f08c968b7530d7e41a8d9761quot;>"
}

syntax:
modify_text_header string
context:

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"
}

syntax:
modify_text_footer string
context:

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/"
}

syntax:
bounce_message_passthrough boolean
default:
no
context:

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
}

syntax:
bcc string
default:
disabled
context:

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]"
}

syntax:
add_email_headers string
default:
disabled
context:

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 valid X-* or List-Help header is allowed.

mail_class orders {
  add_email_headers "X-foo: bar\nX-bar: baz"
}

Disk Space Warning Banner

syntax:
ui_disk_space_warning_threshold percentage [path]
default:
80%
context:

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:

  1. /.
  2. Any mounted filesystem that uses brtfs, ext3, ext4 reiserfs or xfs.

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.

syntax:
ui_disk_space_warning_hide boolean
default:
no
context:

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.

Let’s Encrypt Integration

Also see:

syntax:
lets_encrypt_agree_to_terms_of_service boolean
default:
no
context:

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
}

syntax:
lets_encrypt_registration_email your_email_address
default:
none
context:

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]"
}

syntax:
lets_encrypt_certs_self_check boolean
default:
yes
context:

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
}

syntax:
lets_encrypt_registration_server URI
default:
The production Let's Encrypt registration server
context:

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
}

TLS

syntax:
tls_certificate_files private_key certificate [intermediate]
default:
none
context:

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
}

syntax:
tls_certificate_auto_generate domain_name
default:
none
context:

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
}

Studio Sign-in

syntax:
studio_user_session_activity_timeout duration
default:
none
context:

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
}

syntax:
studio_user_login_lockout_attempt_window duration
default:
15m
context:

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
}

syntax:
studio_user_login_lockout_attempt_count integer
default:
10
context:

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
}

syntax:
studio_user_login_lockout_duration duration
default:
15m
context:

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
}

syntax:
studio_user_login_logfile filename
default:
none
context:

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

syntax:
bee_images_domain domain
default:
`/var/hvmail/control/me`
context:

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

syntax:
studio_disable_subscriber_deletion boolean
default:
no
context:

This configuration directive disables support for deleting subscribers in the Studio UI and API.

general {
  studio_disable_subscriber_deletion yes
}

Click and Open Tracking

syntax:
disable_validating_domain_in_tracking_security
default:
false
context:

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
}

syntax:
disable_validating_all_tracking_security
default:
false
context:

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
}

syntax:
simplemh_generate_click_tracking_id string
default:
never
context:

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 X-GreenArrow-Click-Tracking-ID.

never

Never generate a click tracking ID. If X-GreenArrow-Click-Tracking-ID is not provided, the click tracking ID will be blank. This is the default behavior.

if_not_provided

Generate a click tracking ID only if the incoming email does not include a value for X-GreenArrow-Click-Tracking-ID.

general {
  simplemh_generate_click_tracking_id if_not_provided
}

Server Configuration

syntax:
server_id identifier
default:
none
context:

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"
}

Time

syntax:
engine_time_zone time_zone
default:
system time zone
context:

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:

  1. 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.
  2. 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).
  3. Otherwise, GreenArrow will default to UTC.

Event Delivery

syntax:
event_delivery_destination name { other_directives }
context:
top-level

This grouping directive defines an event delivery destination. The directive event_delivery_url must be defined within this group to engage event delivery.

event_delivery_destination primary {
  event_delivery_url "https://example.com/primary-endpoint"
  event_delivery_events "all"
}

syntax:
event_delivery_url url
default:
none

The URL of this event delivery destination. This should begin with http:// or https://.

event_delivery_destination primary {
  event_delivery_url "https://example.com/primary-endpoint"
  event_delivery_events "all"
}

syntax:
event_delivery_anonymize_localparts boolean
default:
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 anonymized email addresses will look like this (the original domain name is retained):

[email protected]

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
}

syntax:
event_anonymization_constant string
default:
internal constant
context:

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"
}

syntax:
event_delivery_events event_type [, ... ]
default:
all

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)
  • scomp
  • scomp.engine (if you only want to receive SimpleMH events)
  • scomp.studio (if you only want to receive Studio events)
  • 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
}

syntax:
event_delivery_delivery_attempt_config config
default:
see below

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: yes

The delivery attempt ended in success.

status_deferral

boolean, default: no

The delivery attempt ended in deferral.

status_failure

boolean, default: yes

The delivery attempt ended in failure for a reason other than message expiration.

status_failure_toolong

boolean, default: yes

The delivery attempt ended in failure due to message expiration (see queue_lifetime).

status_connmaxout

boolean, default: no

The delivery attempt ended in deferral because of delivery attempt throttling.

include_first_attempt_regardless_of_status

boolean, default: yes

Include the first attempt of all messages, regardless of the status.

include_local_channel

boolean, default: no

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
}

syntax:
event_delivery_max_concurrent_connections concurrency
default:
3

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
}

syntax:
event_delivery_max_batch_size batch_size
default:
100

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
}

syntax:
event_delivery_timeout duration
default:
30s

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.

event_delivery_destination primary {
  event_delivery_url "https://example.com/primary-endpoint"
  event_delivery_timeout 5s
}

syntax:
event_delivery_log_verbose boolean
default:
no

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
}

syntax:
event_delivery_exclude_delivery_attempts_to_mx_hostname hostname [, ... ]

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"
}

syntax:
event_delivery_client_certificate_file private_key_filename certificate_filename

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
}

syntax:
event_delivery_verify_peer boolean
default:
yes

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
}

syntax:
event_delivery_disable_batching boolean
default:
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
}

syntax:
event_delivery_http_keepalive boolean
default:
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
}

syntax:
event_delivery_http_user_agent user-agent
default:
GreenArrow

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"
}

syntax:
event_delivery_format format
default:
json

Specify whether to use json or form. When set to form, the directive event_delivery_disable_batching must be enabled.

When set to (or defaulted to) json:

  • The Content-Type of the HTTP POST will be application/json.
  • The body of the POST 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).

When set to form:

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
}

syntax:
event_delivery_serialize_all_columns boolean
default:
no

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
}


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-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           UP                      UP
hvmail-event-processor    UP                      UP
hvmail-httpd              STARTING
hvmail-logfile-agent      UP                      UP
hvmail-logfile-summary    UP                      UP
hvmail-logfile-writer     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

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
}


Copyright © 2012–2022 GreenArrow Email