This page looks best with JavaScript enabled

SMTP: Difference between MAIL FROM in the envelope and FROM in the message

 ·  🎃 kr0m

Many sysadmins do not understand the difference between the Mail From: field and the From: header of an email, which leads to incorrect configurations of SPF and DKIM records in the DNS zone. In this article, we will clarify all doubts through a brief explanation and a practical case for each scenario.

An email consists of two parts:

  • Envelope: We could say that it is the envelope, if there is any delivery problem it will be returned to this sender.
  • Message: We could say that it is the content of the letter where it indicates to whom it is addressed, who we are, the subject and the rest of the letter.

As with physical letters, the envelope can pass through different post offices and seal the envelope and change the information, but the message will always be the original, the post offices never alter the content of the letter.


In the Envelope, three fields are defined:

  • Received: Every time the email passes through a server, a different Received is added indicating the origin of the email and who receives it, an example can be this email received by GMail from DrWho.alfaexploit.com:
Received: from DrWho.alfaexploit.com ([92.189.150.26])
        by mx.google.com with ESMTPS id h21si1891479wmc.162.2021.09.08.03.01.34
        for <jjivarspoquet@gmail.com>
        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
        Wed, 08 Sep 2021 03:01:34 -0700 (PDT)
  • MAIL FROM: To whom to inform in case of email delivery failure, this information appears in the first Received as envelope-from, in addition, this address will be copied to a new field called Return-Path:
Received: from localhost ([192.168.69.6]) by DrWho.alfaexploit.com (8.16.1/8.16.1) with SMTP id 188A0gJH000912 for jjivarspoquet@gmail.com; Wed, 8 Sep 2021 12:00:51 +0200 (CEST) (envelope-from kr0m@alfaexploit.com)
Return-Path: <kr0m@alfaexploit.com>

We must take into account that in case of email delivery failure, bounced notifications can be notified to the Return-Path address in two different ways depending on the mailing provider.

If we use an email server to send emails (as is the case in most cases), two scenarios can occur:

Hotmail/GMail… delegates to our server Hotmail/GMail… responds directly
The server (SendMail/Postfix…) connects with Hotmail/GMail… The server (SendMail/Postfix…) connects with Hotmail/GMail…
The address does not exist or the mailbox is full The address does not exist or the mailbox is full
Hotmail/GMail… responds through the SMTP connection that it is full Hotmail/GMail… accepts the email
The initial server (SendMail/Postfix…) sends the bounced to the Return-Path address Hotmail/GMail… sends the bounced to the Return-Path address

However, if we make the connection directly against the Hotmail/GMail servers without setting up a SendMail/Postfix, two scenarios can occur:

Hotmail/GMail… delegates to the client Hotmail/GMail… responds directly
The client connects with Hotmail/GMail… The client connects with Hotmail/GMail…
The address does not exist or the mailbox is full The address does not exist or the mailbox is full
Hotmail/GMail… responds through the SMTP connection that it is full Hotmail/GMail… accepts the email
Hotmail/GMail… sends the bounce to the Return-Path address
  • RCPT TO: Email recipient, it is the one that appears in the first Received:
Received: from localhost ([192.168.69.6]) by DrWho.alfaexploit.com (8.16.1/8.16.1) with SMTP id 188A0gJH000912 for jjivarspoquet@gmail.com; Wed, 8 Sep 2021 12:00:51 +0200 (CEST) (envelope-from kr0m@alfaexploit.com)

In the Message we have two parts:

  • Headers: These headers can be of different types, the most common are Subject, Date, From and To, but they can also be data used by certain software such as SpamAssasin, the type of content of the email body among many other options, what I mean is that it can be very variable.
    From: Indicates who the author of the email is.
  • Body: It is the actual content of the email.

We can check the purpose of these fields in their respective RFCs:

RFC5321.MailFrom
RFC5322.From

A Telnet session for sending email could be the following, on the right I indicate a brief description.

-- ENVELOPE:-------------------------
helo localhost
mail from: kr0m@alfaexploit.com             -> Return-Path -> SPF comprobado a partir de este dominio
rcpt to: jjivarspoquet@gmail.com            -> Destinatario real del email
-------------------------------------

-- MESSAGE:--------------------------
data
Subject: SPF: ok DKIM: ok
From: kr0m@alfaexploit.com                  -> Origen mostrado al cliente -> DKIM generado a partir de este dominio
To: to_mostrado@inventado.com               -> Destinatario mostrado al cliente
-------------------------------------

123
.
quit

It is best to try things out for yourself, so I’m going to send different emails:

  • One with all the correct fields.
  • Another with the mail from: from a made-up domain, therefore the SPF will be incorrect.
  • Another with the From: from a made-up domain, therefore we will not sign DKIM.
  • And another with the mail from: and the From: from a made-up domain, so the SPF will be incorrect and we will not sign DKIM.

This way we will see the effect on SPF/DKIM when changing each of the email fields.


Everything is correct:

telnet localhost 25

helo localhost
mail from: kr0m@alfaexploit.com
rcpt to: jjivarspoquet@gmail.com

data
Subject: SPF: ok DKIM: ok
From: kr0m@alfaexploit.com
To: to_mostrado@inventado.com

123
.
quit

We can see the different fields in the email received by the client:

Delivered-To: jjivarspoquet@gmail.com
ARC-Authentication-Results: i=1; mx.google.com;
       dkim=pass header.i=@alfaexploit.com header.s=smtp header.b=IgeEfQnE;
       spf=pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) smtp.mailfrom=kr0m@alfaexploit.com;
       dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=alfaexploit.com
Return-Path: <kr0m@alfaexploit.com>
Received: from DrWho.alfaexploit.com ([92.189.150.26])
        by mx.google.com with ESMTPS id h21si1891479wmc.162.2021.09.08.03.01.34
        for <jjivarspoquet@gmail.com>
        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
        Wed, 08 Sep 2021 03:01:34 -0700 (PDT)
Received-SPF: pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) client-ip=92.189.150.26;
Authentication-Results: mx.google.com;
       dkim=pass header.i=@alfaexploit.com header.s=smtp header.b=IgeEfQnE;
       spf=pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) smtp.mailfrom=kr0m@alfaexploit.com;
       dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=alfaexploit.com
Received: from localhost ([192.168.69.6]) by DrWho.alfaexploit.com (8.16.1/8.16.1) with SMTP id 188A0gJH000912 for jjivarspoquet@gmail.com; Wed, 8 Sep 2021 12:00:51 +0200 (CEST) (envelope-from kr0m@alfaexploit.com)
DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=alfaexploit.com; s=smtp; t=1631095271; bh=Afm/S7SaxS19en1h955RwsupTF914DQUPqYU8Nh7kpw=; h=Subject:From:To; b=IgeEfQnEwaalsc+P0hFiwUykYniP5ulRbLYNiMzbY7dF606Af3W6miP1xst4dPzXI
	 TKTMzNjUBUvIG6bO92hxbwnz41vG9u+g0GH75An78OKC9LfH68pIHeewmiqwbsxoDE
	 8Yg1Z9gVqjhlZOkwSI8mNwOkuS+67wYM9vBISWVY=
Date: Wed, 8 Sep 2021 12:00:42 +0200 (CEST)
Message-Id: <202109081000.188A0gJH000912@DrWho.alfaexploit.com>
Subject: SPF: ok DKIM: ok
From: kr0m@alfaexploit.com
To: to_mostrado@inventado.com
X-Spam-Status: No, score=0.5 required=5.0 tests=ALL_TRUSTED,MISSING_DATE, MISSING_MID autolearn=no autolearn_force=no version=3.4.5
X-Spam-Checker-Version: SpamAssassin 3.4.5 (2021-03-20) on DrWho.alfaexploit.com

123

As we can see, both SPF and DKIM are correct:

       dkim=pass header.i=@alfaexploit.com header.s=smtp header.b=IgeEfQnE;
       spf=pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) smtp.mailfrom=kr0m@alfaexploit.com;
       dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=alfaexploit.com

In the client interface we will see:


Mail from: from a made-up domain, therefore incorrect SPF:

telnet localhost 25

helo localhost
mail from: kr0m@inventado.com
rcpt to: jjivarspoquet@gmail.com

data
Subject: SPF: ko DKIM: ok
From: kr0m@alfaexploit.com
To: to_mostrado@inventado.com

123
.
quit

We can see the different fields in the email received by the client:

Delivered-To: jjivarspoquet@gmail.com
ARC-Authentication-Results: i=1; mx.google.com;
       dkim=pass header.i=@alfaexploit.com header.s=smtp header.b=VCercMLI;
       spf=neutral (google.com: 92.189.150.26 is neither permitted nor denied by best guess record for domain of kr0m@inventado.com) smtp.mailfrom=kr0m@inventado.com;
       dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=alfaexploit.com
Return-Path: <kr0m@inventado.com>
Received: from DrWho.alfaexploit.com ([92.189.150.26])
        by mx.google.com with ESMTPS id l66si1586854wml.114.2021.09.08.03.04.55
        for <jjivarspoquet@gmail.com>
        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
        Wed, 08 Sep 2021 03:04:55 -0700 (PDT)
Received-SPF: neutral (google.com: 92.189.150.26 is neither permitted nor denied by best guess record for domain of kr0m@inventado.com) client-ip=92.189.150.26;
Authentication-Results: mx.google.com;
       dkim=pass header.i=@alfaexploit.com header.s=smtp header.b=VCercMLI;
       spf=neutral (google.com: 92.189.150.26 is neither permitted nor denied by best guess record for domain of kr0m@inventado.com) smtp.mailfrom=kr0m@inventado.com;
       dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=alfaexploit.com
Received: from localhost ([192.168.69.6]) by DrWho.alfaexploit.com (8.16.1/8.16.1) with SMTP id 188A4D8C076084 for jjivarspoquet@gmail.com; Wed, 8 Sep 2021 12:04:19 +0200 (CEST) (envelope-from kr0m@inventado.com)
DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=alfaexploit.com; s=smtp; t=1631095473; bh=Afm/S7SaxS19en1h955RwsupTF914DQUPqYU8Nh7kpw=; h=Subject:From:To; b=VCercMLIzh9ROm9NxxbVEdjNrZWhPRzNerCD5TXpf9hX2J1+BaDeBLw/SU7nXckXH
	 ZeC6wNNfZsvEPeHl1De4xDH5yarUswH5Smcb83biCvnjrF+UDB+C8eq2CZxX8m5vjd
	 DXLzjRVNb3OaBEEWjeY90bEm0AkL/g0+uW2lGXWk=
Date: Wed, 8 Sep 2021 12:04:13 +0200 (CEST)
Message-Id: <202109081004.188A4D8C076084@DrWho.alfaexploit.com>
Subject: SPF: ko DKIM: ok
From: kr0m@alfaexploit.com
To: to_mostrado@inventado.com
X-Spam-Status: No, score=0.8 required=5.0 tests=ALL_TRUSTED, HEADER_FROM_DIFFERENT_DOMAINS,MISSING_DATE,MISSING_MID autolearn=no autolearn_force=no version=3.4.5
X-Spam-Checker-Version: SpamAssassin 3.4.5 (2021-03-20) on DrWho.alfaexploit.com

123

The domain inventado.com is quite permissive since it does not consider our IP as allowed or denied, so GMail considers the SPF as neutral:

       dkim=pass header.i=@alfaexploit.com header.s=smtp header.b=VCercMLI;
       spf=neutral (google.com: 92.189.150.26 is neither permitted nor denied by best guess record for domain of kr0m@inventado.com) smtp.mailfrom=kr0m@inventado.com;
       dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=alfaexploit.com

In the client interface, we will see:


From: from an invented domain, therefore we do not sign DKIM:

telnet localhost 25

helo localhost
mail from: kr0m@alfaexploit.com
rcpt to: jjivarspoquet@gmail.com

data
Subject: SPF: ok DKIM: ko
From: kr0m@inventado.com
To: to_mostrado@inventado.com

123
.
quit

We can see the different fields in the email received by the client:

Delivered-To: jjivarspoquet@gmail.com
ARC-Authentication-Results: i=1; mx.google.com;
       spf=pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) smtp.mailfrom=kr0m@alfaexploit.com
Return-Path: <kr0m@alfaexploit.com>
Received: from DrWho.alfaexploit.com ([92.189.150.26])
        by mx.google.com with ESMTPS id 68si1534562wmz.123.2021.09.08.03.09.08
        for <jjivarspoquet@gmail.com>
        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
        Wed, 08 Sep 2021 03:09:08 -0700 (PDT)
Received-SPF: pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) client-ip=92.189.150.26;
Authentication-Results: mx.google.com;
       spf=pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) smtp.mailfrom=kr0m@alfaexploit.com
Received: from localhost ([192.168.69.6]) by DrWho.alfaexploit.com (8.16.1/8.16.1) with SMTP id 188A8ReQ052051 for jjivarspoquet@gmail.com; Wed, 8 Sep 2021 12:08:33 +0200 (CEST) (envelope-from kr0m@alfaexploit.com)
Date: Wed, 8 Sep 2021 12:08:27 +0200 (CEST)
Message-Id: <202109081008.188A8ReQ052051@DrWho.alfaexploit.com>
Subject: SPF: ok DKIM: ko
From: kr0m@inventado.com
To: to_mostrado@inventado.com
X-Spam-Status: No, score=0.8 required=5.0 tests=ALL_TRUSTED, HEADER_FROM_DIFFERENT_DOMAINS,MISSING_DATE,MISSING_MID autolearn=no autolearn_force=no version=3.4.5
X-Spam-Checker-Version: SpamAssassin 3.4.5 (2021-03-20) on DrWho.alfaexploit.com

123

We see that there is no DKIM header.

DKIM is so important for GMail that to see the email, I had to go to the “All” section because I couldn’t find it in either the inbox or spam.

In the client interface, we will see:


Mail from: from an invented domain and From: also invented, therefore incorrect SPF and no DKIM signature:

telnet localhost 25

helo localhost
mail from: kr0m@inventado.com
rcpt to: jjivarspoquet@gmail.com

data
Subject: SPF: ko DKIM: ko
From: kr0m@inventado.com
To: to_mostrado@inventado.com

123
.
quit

We can see the different fields in the email received by the client:

Delivered-To: jjivarspoquet@gmail.com
ARC-Authentication-Results: i=1; mx.google.com;
       spf=neutral (google.com: 92.189.150.26 is neither permitted nor denied by best guess record for domain of kr0m@inventado.com) smtp.mailfrom=kr0m@inventado.com
Return-Path: <kr0m@inventado.com>
Received: from DrWho.alfaexploit.com ([92.189.150.26])
        by mx.google.com with ESMTPS id n13si1998533wri.475.2021.09.08.03.12.42
        for <jjivarspoquet@gmail.com>
        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
        Wed, 08 Sep 2021 03:12:42 -0700 (PDT)
Received-SPF: neutral (google.com: 92.189.150.26 is neither permitted nor denied by best guess record for domain of kr0m@inventado.com) client-ip=92.189.150.26;
Authentication-Results: mx.google.com;
       spf=neutral (google.com: 92.189.150.26 is neither permitted nor denied by best guess record for domain of kr0m@inventado.com) smtp.mailfrom=kr0m@inventado.com
Received: from localhost ([192.168.69.6]) by DrWho.alfaexploit.com (8.16.1/8.16.1) with SMTP id 188AC1uc019244 for jjivarspoquet@gmail.com; Wed, 8 Sep 2021 12:12:08 +0200 (CEST) (envelope-from kr0m@inventado.com)
Date: Wed, 8 Sep 2021 12:12:01 +0200 (CEST)
Message-Id: <202109081012.188AC1uc019244@DrWho.alfaexploit.com>
Subject: SPF: ko DKIM: ko
From: kr0m@inventado.com
To: to_mostrado@inventado.com
X-Spam-Status: No, score=0.5 required=5.0 tests=ALL_TRUSTED,MISSING_DATE, MISSING_MID autolearn=no autolearn_force=no version=3.4.5
X-Spam-Checker-Version: SpamAssassin 3.4.5 (2021-03-20) on DrWho.alfaexploit.com

123

We see that there is no DKIM header and that the SPF does not pass:

       spf=neutral (google.com: 92.189.150.26 is neither permitted nor denied by best guess record for domain of kr0m@inventado.com) smtp.mailfrom=kr0m@inventado.com

In the client interface, we will see:

Interestingly, this time the email was in the inbox. Without DKIM, we have to look for it in “All,” but without SPF or DKIM, it enters the inbox, things of Google…


In my case, I use OpenDkim, which by default looks at the From: header of the message, but it can be configured to read any other header using the SenderHeaders parameter. The configuration is a list of headers to iterate through in order until one of them is found.

If we need to sign based on some field of the envelope such as Mail From:(Return-Path), we have a problem since Opendkim is limited to the headers of the message and cannot access the fields of the envelope.

To solve this limitation, we can:

  • Inject a header directly into the email with the address of the Mail From:(Return-Path) field.
  • Write a milter that reads the information from the MailFrom:(Return-Path) field and generates a header with that information in the message.

Injecting header:
First, we configure OpenDkim so that if it finds the Custom-Header header, it will read it to obtain the domain with which to sign the email. If it doesn’t find it, it will use the domain of the From header:

vi /usr/local/etc/mail/opendkim.conf

SenderHeaders Custom-Header,From
service milter-opendkim restart

To test it, we will send an email via telnet:

telnet localhost 25

helo localhost
mail from: kr0m@alfaexploit.com
rcpt to: jjivarspoquet@gmail.com

data
Subject: Test OpenDKIM
From: kr0m@inventado.com
To: to_mostrado@inventado.com
Custom-Header: kr0m@alfaexploit.com

123
.
quit

The result is as follows:

Delivered-To: jjivarspoquet@gmail.com
ARC-Authentication-Results: i=1; mx.google.com;
       dkim=pass header.i=@alfaexploit.com header.s=smtp header.b=gL9fSNRb;
       spf=pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) smtp.mailfrom=kr0m@alfaexploit.com
Return-Path: <kr0m@alfaexploit.com>
Received: from DrWho.alfaexploit.com ([92.189.150.26])
        by mx.google.com with ESMTPS id r9si895119wru.150.2021.09.08.23.47.51
        for <jjivarspoquet@gmail.com>
        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
        Wed, 08 Sep 2021 23:47:52 -0700 (PDT)
Received-SPF: pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) client-ip=92.189.150.26;
Authentication-Results: mx.google.com;
       dkim=pass header.i=@alfaexploit.com header.s=smtp header.b=gL9fSNRb;
       spf=pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) smtp.mailfrom=kr0m@alfaexploit.com
Received: from localhost ([192.168.69.6]) by DrWho.alfaexploit.com (8.16.1/8.16.1) with SMTP id 1896kuWO076701 for jjivarspoquet@gmail.com; Thu, 9 Sep 2021 08:47:08 +0200 (CEST) (envelope-from kr0m@alfaexploit.com)
DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=alfaexploit.com; s=smtp; t=1631170048; bh=Afm/S7SaxS19en1h955RwsupTF914DQUPqYU8Nh7kpw=; h=Subject:From:To; b=gL9fSNRb6ovDOSOC+01X2F29evKpDQ7Rnr50ZDxocA3bgWopsa8v2WMci5U8PFAxq
	 6prYxfHIQad77IbZaRy7pca4+wi3rjILFE6lcZKssHcc5LpZjTLlikxmJmKWLjg6PF
	 QGFiJeoHFzrsEIHcgm6oX71nZ1uflG3nTyEB1UAY=
Date: Thu, 9 Sep 2021 08:46:56 +0200 (CEST)
Message-Id: <202109090647.1896kuWO076701@DrWho.alfaexploit.com>
Subject: Test OpenDKIM
From: kr0m@inventado.com
To: to_mostrado@inventado.com
Custom-Header: kr0m@alfaexploit.com
X-Spam-Status: No, score=0.8 required=5.0 tests=ALL_TRUSTED, HEADER_FROM_DIFFERENT_DOMAINS,MISSING_DATE,MISSING_MID,TVD_SPACE_RATIO autolearn=no autolearn_force=no version=3.4.5
X-Spam-Checker-Version: SpamAssassin 3.4.5 (2021-03-20) on DrWho.alfaexploit.com

123

As we can see, OpenDkim has read the custom header and not From. If it had read the From header, it would have tried to sign the email with the invented.com domain, which is not owned by me, and the email would have arrived without a DKIM signature. But since it has read the Custom-Header header, it has signed it correctly with alfaexploit.com.

Through milter:
First, we configure OpenDkim so that if it finds the Custom-Header header, it will read it to obtain the domain with which to sign the email. If it doesn’t find it, it will use the domain of the From header:

vi /usr/local/etc/mail/opendkim.conf

SenderHeaders Custom-Header,From
service milter-opendkim restart

We program a simple milter that will read the mail from field of the envelope and add the Custom-Header header with that information:

vi kr0mMilterReturnPath.py
#!/usr/bin/env python
# https://pythonhosted.org/pymilter/classMilter_1_1Base.html

import Milter
import time
import sys
import os
import logging
import logging.handlers


from configparser import ConfigParser

__version__ = '0.5b'  # version

CONFIG = os.path.join(os.path.dirname(__file__),"config.ini")

if os.path.isfile(CONFIG):
	config = ConfigParser()
	config.read(CONFIG)
	SOCKET = config.get('Milter', 'SOCKET')
	try:
		UMASK = int(config.get('Milter', 'UMASK'), base=0)
	except:
		UMASK = 0o0077
	TIMEOUT = config.getint('Milter', 'TIMEOUT')
	MAX_FILESIZE = config.getint('Milter', 'MAX_FILESIZE')
	LOGFILE_DIR = config.get('Logging', 'LOGFILE_DIR')
	LOGFILE_NAME = config.get('Logging', 'LOGFILE_NAME')
	LOGLEVEL = config.getint('Logging', 'LOGLEVEL')
else:
	sys.exit("Please check the config file! Config path: %s" % CONFIG)

# =============================================================================

LOGFILE_PATH = os.path.join(LOGFILE_DIR, LOGFILE_NAME)
log = logging.getLogger('kr0mMilter')
log.setLevel(logging.CRITICAL+1)

class kr0mMilter(Milter.Base):
    def __init__(self):
        self.id = Milter.uniqueID()
        self.return_path_domain = None

    def envfrom(self, mailfrom, *str):
        self.return_path_domain = mailfrom
        return Milter.CONTINUE

    def eom(self):
        self.addheader('Custom-Header', self.return_path_domain)
        return Milter.CONTINUE

# =============================================================================

def main():
	try:
		os.makedirs(LOGFILE_DIR,0o0027)
	except:
		pass

	oldumask = os.umask(0o0026)
	handler = logging.handlers.WatchedFileHandler(LOGFILE_PATH, encoding='utf8')
	formatter = logging.Formatter('%(asctime)s - %(levelname)8s: %(message)s')
	handler.setFormatter(formatter)
	log.addHandler(handler)
	os.umask(oldumask)

	if LOGLEVEL == 2:
		log.setLevel(logging.INFO)
	elif LOGLEVEL == 3:
		log.setLevel(logging.WARNING)
	else:
		log.setLevel(logging.DEBUG)

	Milter.factory = kr0mMilter
	flags = Milter.CHGBODY + Milter.CHGHDRS + Milter.ADDHDRS
	flags += Milter.ADDRCPT
	flags += Milter.DELRCPT
	Milter.set_flags(flags)

	print("%s kr0mMilter startup - Version %s" % (time.strftime('%Y-%m-%d %H:%M:%S'), __version__ ))
	print('logging to file %s' % LOGFILE_PATH)

	log.info('Starting kr0mMilter v%s - listening on %s' % (__version__, SOCKET))
	log.debug('Python version: %s' % sys.version)
	sys.stdout.flush()

	os.umask(UMASK)

	Milter.set_exception_policy(Milter.ACCEPT)
	Milter.runmilter("kr0mMilter", SOCKET, TIMEOUT)
	print("%s kr0mMilter shutdown" % time.strftime('%Y-%m-%d %H:%M:%S'))

if __name__ == "__main__":
	main()

We configure our MTA to use the milter.
SendMail:

cd /etc/mail

We define the milter and add it to the confINPUT_MAIL_FILTERS list:

vi DrWho.alfaexploit.com.mc

MAIL_FILTER(`kr0mMilter', `S=/var/run/kr0mMilter.sock, F=T, T=R:2m')
define(`confINPUT_MAIL_FILTERS', `kr0mMilter, spamassassin, dkim-filter')

NOTE: The order of the milters is important, we must first execute our milter and then OpenDkim.

We compile the new configuration into M4:

make

We update the Sendmail configuration with ours:

cp DrWho.alfaexploit.com.cf sendmail.cf

We restart the service:

service sendmail restart

Postfix:
We edit its configuration as follows:

vi /etc/postfix/main.cf

smtpd_milters = unix:/var/run/kr0mMilter.sock, unix:/var/run/opendkim/opendkim.sock

NOTE: The order of the milters is important, we must first execute our milter and then OpenDkim.

We restart the service:

service postfix restart

To test it, we will send an email via telnet:

telnet localhost 25

helo localhost
mail from: kr0m@alfaexploit.com
rcpt to: jjivarspoquet@gmail.com

data
Subject: Test2 OpenDKIM
From: kr0m@inventado.com
To: to_mostrado@inventado.com

123
.
quit

The result is as follows:

Delivered-To: jjivarspoquet@gmail.com
ARC-Authentication-Results: i=1; mx.google.com;
       dkim=pass header.i=@alfaexploit.com header.s=smtp header.b=oP11og1A;
       spf=pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) smtp.mailfrom=kr0m@alfaexploit.com
Return-Path: <kr0m@alfaexploit.com>
Received: from DrWho.alfaexploit.com ([92.189.150.26])
        by mx.google.com with ESMTPS id l26si993677wmi.106.2021.09.09.00.09.57
        for <jjivarspoquet@gmail.com>
        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
        Thu, 09 Sep 2021 00:09:57 -0700 (PDT)
Received-SPF: pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) client-ip=92.189.150.26;
Authentication-Results: mx.google.com;
       dkim=pass header.i=@alfaexploit.com header.s=smtp header.b=oP11og1A;
       spf=pass (google.com: domain of kr0m@alfaexploit.com designates 92.189.150.26 as permitted sender) smtp.mailfrom=kr0m@alfaexploit.com
Received: from localhost ([192.168.69.6]) by DrWho.alfaexploit.com (8.16.1/8.16.1) with SMTP id 1897974Z026004 for jjivarspoquet@gmail.com; Thu, 9 Sep 2021 09:09:15 +0200 (CEST) (envelope-from kr0m@alfaexploit.com)
DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=alfaexploit.com; s=smtp; t=1631171373; bh=osFg1QXCH8704iYyd9cTTQI3SShRGx5igJ1ovGCgJ4s=; h=Subject:From:To; b=oP11og1ArQj5GSBPoX9nV6/sBL7a3tkGGPS55fiBh2pTN42C3sFirKZ4SFiWcw6Hy
	 U1OxNrNQdVeQ0TIc7N2qE1hiNdXPBhfMtX77lXdsNJBW7KmFzJ9R8oHz+k4ikw4kS+
	 kcMRcqanDvkXqBNwqetk2qffkr5WQ2kV+J5kxLSQ=
Date: Thu, 9 Sep 2021 09:09:07 +0200 (CEST)
Message-Id: <202109090709.1897974Z026004@DrWho.alfaexploit.com>
Subject: Test2 OpenDKIM
From: kr0m@inventado.com
To: to_mostrado@inventado.com
Custom-Header: kr0m@alfaexploit.com
X-Spam-Status: No, score=0.8 required=5.0 tests=ALL_TRUSTED, HEADER_FROM_DIFFERENT_DOMAINS,MISSING_DATE,MISSING_MID autolearn=no autolearn_force=no version=3.4.5
X-Spam-Checker-Version: SpamAssassin 3.4.5 (2021-03-20) on DrWho.alfaexploit.com

data
123

As we can see, OpenDkim has read the custom header and not From. If it had read the From header, it would have tried to sign the email with the invented.com domain that is not owned by me, and the email would have arrived without a DKIM signature. However, since it has read the Custom-Header header, it has signed it correctly with alfaexploit.com.


In conclusion, we can assure that SPF and DKIM read different data to evaluate the validity of the email:

  • SPF: Reads the domain of the Mail From: from the envelope.
  • DKIM: Reads the domain of the message header that we indicate through the SenderHeaders configuration parameter, by default From:.
If you liked the article, you can treat me to a RedBull here