When managing shared hosting environments based on cPanel/WHM, I’ve often seen users encountering mailing issues because of misconfiguration that can make email functionality a bit of a headache: SPF record failures. These failures cause emails to be rejected by recipient services—a major frustration, especially for WordPress users.
The Problem: Mismatched Sender Address and SPF Record
In a typical cPanel/WHM shared hosting setup, the server hostname might look something like cluster-5e8d1.tld or a subdomain such as cluser-698445.company.tld. this server includes many accounts/users, each with a domain and maybe a different or shared IP addressed such as domain1.com, domain2.com, domain3.com, etc. Now, when a cPanel user installs WordPress either manually, or through WP Toolkit or Softaculous, their default email addresses are often like: [email protected] or [email protected].
However, when WordPress sends emails, it uses PHP’s mail() function, with the actual headers often looking like this:
- Sender:
[email protected] - FROM:
cpaneluser@serverhostname
This mismatch occurs because the FORM header isn’t explicitly defined at the level of wp_mail() which uses the native PHP mail() function, which again relies on the system exim sendmail. On the other hand, if Exim is not explicitly provided with a FORM header (i.e.sendmail_from value) —it falls back to a form including the username from which the command was executed at the hostname, something similar to using $USER or $(whoami)@$(hostname). The problem? The server hostname (cluster1.com) may not include the required SPF records for the IP of the domain (wpdomain.com). This discrepancy results in emails being flagged as suspicious or outright rejected by recipient mail services.
grep sendmail /opt/alt/php74/etc/php.ini ; For Win32 only.;sendmail_from = [email protected]; For Unix only. You may supply arguments as well (default: "sendmail -t -i").sendmail_path = /usr/sbin/sendmail -t -i
Exploring Solutions
After understanding the root cause of the issue, we can easily identify three potential solutions, each with its own scope and implications:
1. Adding SPF Records for the Server Hostname
One simple solution is to include the IP addresses used for sending emails in the server hostname’s SPF record. For example, adding this TXT record to cluster1.com:
v=spf1 include:_spf.company.tld ~allThis ensures emails sent from [email protected] comply with SPF requirements. While straightforward, this approach still uses the server’s hostname, which may not align with users’ preferences or the company’s policy in allowing the users to safely use its hostname in sending forged emails with a custom from like [email protected].
2. Using SMTP for Outgoing Emails
Another option is to encourage WordPress users to configure SMTP for outgoing emails. By setting up an SMTP plugin (such as WP Mail SMTP), users can send emails directly from their own domain. This approach bypasses the server hostname issue entirely; however, it’s impractical for managing large numbers of users across various web solutions.
3. Enforcing the Use of Domain-Specific Senders
The third solution involves configuring PHP to enforce the use of a domain-specific “FROM” header, ensuring compatibility with SPF records. Here’s how this can be implemented:
- In
.php.inior .user.ini:
Add the following line to define a default sender:which can also substituted through .htaccesssendmail_from = "[email protected]" - In
wp-config.php(for WordPress):
Inject the setting programmatically using:ini_set('sendmail_from', '[email protected]'); - Using a WordPress filter:
Modify the sender address dynamically:add_filter('wp_mail_from', function($email) { return '[email protected]';});
Automating the Process: My Approach
Given that shared hosting environments can have dozens (or hundreds) of accounts, I needed an automated way to apply this configuration for all users. Here’s what I came up with:
Automated Script to Inject sendmail_from
Updating .htaccess files for each cPanel user with the appropriate sendmail_from setting:
#!/bin/bash# Script path: /myscripts/php_sendmail_injector.sh# This script updates .htaccess files for cPanel users by injecting# a "sendmail_from" configuration, ensuring proper email handling when using PHP mail()# TODO: I remember that this issue is also found in python/Django, to check# Logs actions to a file for easy tracking:LOG_FILE="/myscripts/logs/sendmail_injector.log"# Function to print to both console and log fileprint_log() { local message="$1" echo "$message" # Print to console echo "$(date '+%Y-%m-%d %H:%M:%S') - $message" >> "$LOG_FILE" # Log with timestamp}print_log "********** PHP Sendmail Injector was run **********"# Get list of cPanel users and their domainswhmapi1 listaccts --output=json | jq -r '.data.acct[] | "\(.user) \(.domain)"' | while read -r cpuser domain; do # Check if both cPanel user and domain are non-empty if [[ -n "$cpuser" && -n "$domain" ]]; then htaccess_path="/home/$cpuser/.htaccess" # Check if .htaccess exists and ensure it doesn't already contain sendmail_from if [[ ! -f "$htaccess_path" ]] || ! grep -q "sendmail_from" "$htaccess_path"; then # Add sendmail_from line to the .htaccess file echo "php_value sendmail_from \"noreply@$domain\"" >> "$htaccess_path" chown "$cpuser":"$cpuser" "$htaccess_path" chmod 644 "$htaccess_path" print_log "Injected: sendmail_from to $htaccess_path for $cpuser ($domain)" #else # print_log "Skipped: $htaccess_path already exists and contains sendmail_from" fi fidoneexit 0This script automates the following:
- Retrieves all cPanel users and their associated domains.
- Checks if the
.htaccessfile exists for each user and whether it already contains thesendmail_fromdirective. - If not, appends the directive using the user’s domain.
It can be set as scheduled cron task and set up initially as a hook at the creation of a new account.

Comments