You are here

DMARC Policies are eating my Drupal emails!

Corey Pennycuff's picture
Spam_Mail.png
Spam is bad! Kill it with fire!
Image from openclipart.org.

Due to the irritating nature of spam email, companies have started hardening their policies for how they handle emails that originate from various sources. A recent change that has hurt a lot of sites and mailing lists lately is that email providers have begun to make their DMARC policies very strict. Specifically, email providers are saying, "If the email says that it is from one of our email servers, but it didn't come from our server, then deny the message." (I'm looking at you, Yahoo! and AOL!) This in and of itself is not the whole problem. The recipient email service must agree to respect DMARC policies. When they do, emails that say that they are from a domain, but are from somewhere else, are silently rejected.

"But wait," you say, "this sounds totally reasonable!" You're right. And wrong. And right. Let's just get this sorted out.

The Problem

There are times when a system sends out email on behalf of a user, even though that user's email is not on the said system. Think of a mailing list. It is normal for a mailing list to send email to many users on behalf of the person actually sending the email. In fact, it's a very common occurrence, in so much that the recent DMARC policy hardening has negatively impacted many reputable mailing list services.

In Drupal, we have the Contact form. When someone fills out a contact form, they provide their email address, and Drupal, in turn, sends an email to the site owner, saying that it is from the email address of the person who filled out the contact form. Many businesses use the contact form for customer and sales information. With the recent DMARC hardening, it is entirely possible for those precious messages from customers to be silently eaten by the Internets.

In order for this to happen, 3 things must occur.

  1. The recipient's email service must honor DMARC policies of other servers. (Hello, Gmail! Probably others, too.)
  2. The sender's address must have a DMARC reject policy for emails not originating from their own servers. (Yahoo!, AOL, and perhaps many others.)
  3. The script (in this case, Drupal) must send out the email on behalf of the problem email address (eg. Yahoo!, AOL) to a problem receiver (eg. Gmail).

In other words, it is entirely possible for some messages to come through (because of a less-strict DMARC policy from one server), while others are lost entirely.

Fixing this with Drupal

The fix for this is relatively simple, although it requires a little bit of code. The main fix is, for all outgoing emails, move the from address to the reply-to field, and then set the from address to be the site email. There is a module on drupal.org that addresses some of this problem, but I don't think it goes far enough. It only protects contact forms, while my solution covers all emails. (This is, of course, assuming that the site email is on the same domain. Otherwise, you will have to edit the code to use an appropriate email address.)

My solution uses hook_mail_alter() to intercept all emails and make the change. The module code can be seen below. I am calling my module MC for "Mail Corrector".

<?php
/**
 * Implements hook_mail_alter().
 */
function mc_mail_alter(&$message) {
  $contact_email = $message['from'];
  $contact_name = isset($message['params']['name']) ? $message['params']['name'] : $contact_email;
  $site_name = variable_get('site_name', '');
  $site_mail = variable_get('site_mail', 'nobody@example.com');
 
  $message['headers']['Reply-To'] = $message['from'];
  $message['from'] = $message['headers']['From'] = t("@site_name <@site_mail>", array('@contact_name' => $contact_name, '@contact_email' => $contact_email, '@site_name' => $site_name, '@site_mail' => $site_mail));
}

Of course, you could also create an install hook to set the module's weight to be very heavy, so that it runs after all the other modules.

<?php
/**
 * Implements hook_install().
 */
function mc_install() {
  db_update('system')
    ->fields(array('weight' => 99))
    ->condition('name', 'mc')
    ->execute();
}

Finally, If you're going to make this into a proper module, you might as well have a .info file:

name = Mail Corrector
description = Sets all mail to be from the site email, and changes the original email's sender to reply-to.
core = 7.x

Of course, some of you want to download the module directly, so I provided a zip file of the module at the end of this post. It has no configurations, it just starts working when you enable it.

The Good Side of all of this

What makes a strong DMARC policy good is that it cuts down on spam, pure and simple. How many time have the less-computer-savvy said, "Oh, No! People are saying that I'm sending them emails with a virus! I've been hacked!!!!!" In truth, it is very easy to send an email claiming that you are someone else. These strong DMARC policies are simply the email provider's way of fighting back, by asking that other email providers do not accept these emails if it did not come directly from them. All in all, this is a win for everyone.

Tags: 

Files: 

AttachmentSize
Package icon mc.zip1.1 KB