Sendmail Configuration for Laravel: A Comprehensive Guide

Introduction

Sendmail is a classic Mail Transfer Agent (MTA) that facilitates email delivery on Unix-based systems. While modern alternatives such as Postfix and Exim have gained popularity, Sendmail remains a crucial tool for legacy systems, deep troubleshooting, and custom setups. This guide aims to provide a comprehensive understanding of configuring Sendmail for Laravel without advocating it as the primary choice. It's a deep dive, drawing from the provided documentation, to help you master Sendmail's intricacies. This is not a recommendation to use it everywhere, but rather a valuable skill for specific situations.

Laravel offers flexibility in handling various mail drivers, including SMTP, Mailgun, Postmark, Amazon SES, and Sendmail. While Sendmail isn't typically the default choice due to its complexity and security considerations, it can be beneficial in specific cases:

Sendmail Configuration Files: The Basics

Sendmail configuration revolves around .mc files, which are processed by the m4 macro processor to generate .cf configuration files. It's important to know that .mc files are human-readable, while .cf files are not meant to be edited directly. The m4 processor compiles .mc files into .cf files, treating the input as a stream rather than line by line, making the order of directives crucial.

To convert an .mc file to a .cf file, you would typically use a command like this:

m4 ${CFDIR}/m4/cf.m4 config.mc > config.cf

${CFDIR} usually refers to /etc/mail/ or a similar location.

Anatomy of a .mc File

The general structure of an .mc file is important to understand. The order of the directives matters. Key elements include:

Macro definitions that influence a FEATURE() should be defined before that feature.

Essential Directives in .mc Files

Understanding the M4 Macro Processor

Sendmail uses m4 to compile configuration files. m4 processes input as a stream rather than line by line. The dnl command, short for "delete through newline," is used for commenting out lines or parts of lines in .mc files. Macros are expanded even within comments, which may lead to unexpected behaviour.

File Locations and the MAIL_SETTINGS_DIR Macro

The MAIL_SETTINGS_DIR macro defines where Sendmail looks for configuration files, typically /etc/mail/. All filenames in .mc or .cf files should be absolute paths for consistency and security.

Operating System Definitions (ostype Files)

Each OS has predefined settings in ostype files, such as ALIAS_FILE and QUEUE_DIR. Customising these ensures optimal performance. These files may be empty if the defaults are sufficient. The list of configuration-supported systems is not as broad as the list of source-supported systems.

Domains

Domain-dependent definitions can be collected into a file referenced by the DOMAIN macro. This file can include local names, domain names using DD, and site-wide features. MASQUERADE_AS can be defined in this file if all hosts at the site masquerade behind one name. Defining a domain is optional and may not be worth the effort for single-machine setups. Domain files help in organizing "domain-dependent knowledge".

Mailers

Sendmail supports various mailers:

MAILER definitions should be placed at the end of the .mc file.

Features

FEATURE macros are used to add optional functionalities. A feature can have up to 9 optional parameters. The database map type defaults to Berkeley DB hash format but can be set with define('DATABASE_MAP_TYPE', 'dbm').

Common features include:

Hacks

Site-dependent configurations that are not considered features are placed in the hack subdirectory and referenced using the HACK macro. These tend to be site-dependent.

Site Configuration

Complex sites might need local configurations, such as lists of UUCP hosts. The SITECONFIG macro can indirectly reference site-dependent information. This section is mostly obsolete, and mailertables should be used instead.

UUCP Mailer Variations

There are differences between uucp-old, uucp-new, uucp-dom, and uucp-uudom mailers, especially regarding address handling. Sender rewriting is handled differently for different UUCP mailers.

Tweaking Rulesets

LOCAL_RULE_3 can be used to define custom rules for canonicalizing names, which are reflected in the header. The UUCPSMTP macro is used for converting old UUCP addresses to SMTP addresses. Rulesets 1 and 2 can be tweaked using LOCAL_RULE_1 and LOCAL_RULE_2. The LOCAL_CONFIG macro adds lines after boilerplate option settings but before rulesets, and can be used for declaring database maps.

Masquerading and Relaying

LOCAL_RELAY applies to unqualified names, MAIL_HUB to names qualified with the local host name, and SMART_HOST to names qualified with other hosts or bracketed addresses.

Using LDAP for Aliases, Maps, and Classes

LDAP can be used for alias lookups using the ALIAS_FILE option. The default LDAP schema can be used, or a custom one specified when setting ALIAS_FILE. LDAP can also be used for maps, including access_db, authinfo, bitdomain, domaintable, genericstable, mailertable, uucpdomain, and virtusertable. The map parameters can be customized when using the FEATURE() macro. Classes can be filled via map lookups using the @ldap: syntax. These classes can be used with commands such as RELAY_DOMAIN_FILE(), MASQUERADE_DOMAIN_FILE() etc. Macros cannot be used in class declarations.

LDAP Routing

FEATURE('ldap_routing') can be used to implement LDAP-based routing. The LDAP lookup is done on the full address and then the domain portion. LDAPROUTE_EQUIVALENT is also used. The default behavior of FEATURE('ldap_routing') can be modified using additional arguments.

Anti-Spam Configuration Control

Relaying is denied by default. FEATURE('promiscuous_relay') can be used to revert to the old behavior, but should be avoided. RELAY_DOMAIN() and RELAY_DOMAIN_FILE() add domains or IP addresses to class {R}. FEATURE('relay_entire_domain') can also be used. FEATURE('relay_local_from') should be avoided. FEATURE('relay_mail_from') is a slightly better option. Source routing is used, and the effects of using FEATURE('loose_relay_check') should be considered. UUCP addresses can be used to bypass anti-spam rules. FEATURE('accept_unresolvable_domains') can be used. FEATURE('accept_unqualified_senders') accepts senders with unqualified addresses. The access_db feature can be enabled and used, and an access database created.

Examples of entries in the access database include: REJECT, SKIP, ERROR:, OK, RELAY, and specific error codes. FEATURE('relay_hosts_only') can also be used. Sender addresses can be blocked using FEATURE('blacklist_recipients'). Tags such as From:, To:, and Connect: can be used in the access database for more specific filtering. The delay_checks feature delays the check_mail and check_relay rulesets and the Spam: tag. LOCAL_RULESETS can implement header checks.

STARTTLS

STARTTLS can be configured by setting the confCACERT_PATH, confCACERT, confSERVER_CERT, confSERVER_KEY, and confRAND_FILE variables. SMTP STARTTLS allows relaying for authenticated senders in the RelayAuth ruleset, using the CERTISSUER tag. Examples of allowing relaying for certificates signed by a specific authority can be found in the sources. The tls_server, tls_client, and tls_rcpt rulesets control accepted connections. The access map can be used with tags such as TLS_Srv, TLS_Clt, and TLS_Rcpt. ENCR, VERIFY, and CN in the TLS settings have specific meanings. Examples of enforcing encryption and authentication rules for specific domains can be found in the sources. Try_TLS and Srv_Features can be used to disable STARTTLS for broken MTAs. The Received: header reveals whether STARTTLS has been used.

SMTP Authentication

The auth_authen, auth_author, and auth_type macros are used for anti-relay rulesets, and Local_trust_auth is used for trusting the AUTH= parameter. Relaying is allowed by default for any user authenticated via trusted mechanisms defined by TRUST_AUTH_MECH(). The authinfo ruleset provides authentication data for client MTA.

Adding New Mailers or Rulesets

New mailers or rulesets can be introduced using MAILER_DEFINITIONS and LOCAL_RULESETS, respectively. Local additions for srv_features, try_tls, tls_rcpt, tls_client, and tls_server can be made using LOCAL_SRV_FEATURES, LOCAL_TRY_TLS, LOCAL_TLS_RCPT, LOCAL_TLS_CLIENT, and LOCAL_TLS_SERVER.

Adding New Mail Filters

Mail filters can be added using MAIL_FILTER() and INPUT_MAIL_FILTER(). INPUT_MAIL_FILTER() populates confINPUT_MAIL_FILTERS with the name of the filter. The list of filters can be reset by setting confINPUT_MAIL_FILTERS.

Queue Group Definitions

Queue groups can be defined using QUEUE_GROUP(). Refer to the Sendmail documentation for more details.

Non-SMTP Based Configurations

Configuration files may have limitations for non-SMTP sites. SMART_HOST can be used to route messages with a richer address syntax. LOCAL_NET_CONFIG adds appropriate rules for SMTP-based sites connecting via UUCP. Anti-spam rules may need to be disabled using FEATURE('promiscuous_relay') and FEATURE('accept_unresolvable_domains').

Who Am I?

The $j macro is automatically defined to be the fully qualified domain name (FQDN). The confDOMAIN_NAME macro can be defined in cases where gethostbyname() does not return the FQDN.

Accepting Mail for Multiple Names

Class {w} can be augmented for hosts known by several names. This can be done by creating the /etc/mail/local-host-names file with a list of host aliases or using LOCAL_DOMAIN(). The virtusertable feature can be used for different addresses in different domains.

Using Mailertables

An external database can be created using FEATURE('mailertable') for routing information. Examples of mailertable entries include domain, host-specific, and bitnet routing. makemap creates the database version of the mailertable. Matching rules in mailertables include matching order, wildcards, and the use of %1 to interpolate wildcarded parts. The right-hand side of a mailertable entry should always be a mailer:host pair. Creating MX loops when using mailertables should be avoided.

Using Userdb to Map Full Names

The user database is not intended for mapping full names to login names. Aliases are recommended instead. The user database is used to locate the default maildrop. FEATURE('stickyhost') should not be used when using the user database to map full names. makemap builds the internal form of the user database. Using full names as email addresses is generally discouraged.

Miscellaneous Special Features

Plussed users can be used for centralized mail configuration with root mail forwarding.

Security Notes

Security depends on the user, and Sendmail 8 is more secure than previous versions. Essential security practices include:

Integrating Sendmail with Laravel

To configure Laravel to use Sendmail, you need to update the .env file and config/mail.php:

  1. Update .env:

    MAIL_MAILER=sendmail
    MAIL_SENDMAIL="/usr/sbin/sendmail -bs"
    

    For Laravel 7 and above use MAIL_MAILER, earlier versions use MAIL_DRIVER.

  2. Update config/mail.php:

    return [
      'default' => env('MAIL_MAILER', 'sendmail'),
       'mailers' => [
           'sendmail' => [
               'transport' => 'sendmail',
               'path' => env('MAIL_SENDMAIL', '/usr/sbin/sendmail -bs'),
           ],
       ],
    ];
    
  3. Ensure that MAIL_SENDMAIL in your .env is set to the correct path to the Sendmail executable. Often, this is /usr/sbin/sendmail -t -i or /usr/sbin/sendmail -bs.

  4. You may need to clear the configuration cache after making these changes

php artisan config:cache

Debugging Sendmail Issues

Sendmail Tips and Tricks

Conclusion

Sendmail, despite its complexity, is a powerful and flexible MTA. When integrated correctly with Laravel, it provides direct email control, suitable for specific use cases. By following best practices in security, configuration management, and debugging, Laravel applications can reliably send emails via Sendmail.

This guide serves as a reference for developers working with Laravel and Sendmail, ensuring a robust and secure configuration.