Skip to main content

Configurando DKIM con Postfix

DKIM es un standard de internet que permite relacionar un mensaje de correo con un nombre de dominio, utiliza un cifrado de clave asimétrica para poder validar un mensaje de correo con su emisor. El MTA del emisor firma los mensajes de correo con la clave privada y el receptor puede validar a partir de la clave pública obtenida del dominio del emisor que las cabeceras del mensaje no han sido alteradas.

Instalar OpenDKIM y sus dependencias:

sudo apt-get install opendkim opendkim-tools

Editar el fichero /etc/opendkim.conf

AutoRestart             Yes
AutoRestartRate         10/1h
UMask                   002
Syslog                  yes
SyslogSuccess           Yes
LogWhy                  Yes

Canonicalization        relaxed/simple

ExternalIgnoreList      refile:/etc/opendkim/TrustedHosts
InternalHosts           refile:/etc/opendkim/TrustedHosts
KeyTable                refile:/etc/opendkim/KeyTable
SigningTable            refile:/etc/opendkim/SigningTable

Mode                    sv
PidFile                 /var/run/opendkim/
SignatureAlgorithm      rsa-sha256

UserID                  opendkim:opendkim

Socket                  inet:12301@localhost

Esto es un ejemplo de configuración que permite firmar mensajes para varios dominios, para ver con mayor detalle la configuración puedes ir aquí

Conectar el filtro milter con Postfix

editar el fichero /etc/default/opendkim y añadir la siguiente línea:


Editar el fichero /etc/postfix/ de postfix y asegurarse de que estas opciones existen:

milter_protocol = 2
milter_default_action = accept

Si no tienes más filtros milter configurados añadir las siguientes líneas:

smtpd_milters = inet:localhost:12301
non_smtpd_milters = inet:localhost:12301

Crear la estructura de directorios para albergar las claves y los ficheros de configuración de OpenDKIM:

sudo mkdir -p /etc/opendkim/keys

Especificar el fichero de servidores de confianza:

vim /etc/opendkim/TrustedHosts



Crear el fichero KeyTable con la tabla de claves, la tabla contiene el par selector/dominio y la ruta a la clave privada a utilizar para firmar los mensajes:

vim /etc/opendkim/KeyTable

Crear el fichero SigningTable. El fichero se utiliza para especificar los dominios y sus selectores:

vim /etc/opendkim/SigningTable

Generar el par de claves para cada dominio:

cd /etc/opendkim/keys
opendkim-genkey -s mail -d
chown opendkim:opendkim mail.private

Añade la clave pública al registro DNS
Por cada dominio abre el fichero mail.txt

mail._domainkey IN TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDN12F+VM4TCEMm8/5vGjhT42Zo/UHbf+N6CZx5Aj3p20u1dR8mqeWLM3TqE+9EpvKsx4GKtrl/8QBL1g7ZmdluVSlz6AIMarDXnjqmKqN4dlpCj15bnOjiHxH6r/bpll36dJrlmRuOL61xnilxTydpWQ4uJtTel2eUG5zeUG1CnQIDAQAB" ; ----- DKIM key mail for

Puedes probar que tu DNS responde correctamente a través del comando dig:

dig txt
;; ANSWER SECTION: 14400 IN	TXT	"v=DKIM1\; k=rsa\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDN12F+VM4TCEMm8/5vGjhT42Zo/UHbf+N6CZx5Aj3p20u1dR8mqeWLM3TqE+9EpvKsx4GKtrl/8QBL1g7ZmdluVSlz6AIMarDXnjqmKqN4dlpCj15bnOjiHxH6r/bpll36dJrlmRuOL61xnilxTydpWQ4uJtTel2eUG5zeUG1CnQIDAQAB"

Una vez que está todo correcto reinicia el servicio de OpenDKIM y Postfix

# service opendkim restart
# service postfix restart

y para probar que la configuración es correcta envía un mail a la dirección, el servicio nos responderá con un mensaje en el que se

Summary of Results
SPF check:          pass
DomainKeys check:   neutral
DKIM check:         pass
Sender-ID check:    pass
SpamAssassin check: ham

550 Message does not pass DomainKeys requirements for domain

I got this error from my mail server log when attempting to send a mail to one of our clients:

/var/log/syslog.4.gz:Dec 14 18:13:01 XXXXXX postfix/smtp[26150]: 01BA812B22C: to=<>,[]:25, delay=0.11, delays=0.03/0.01/0.02/0.05, dsn=5.0.0,
status=bounced (host[] said: 550 Message does not pass DomainKeys requirements
 for domain (in reply to end of DATA command))

I’ve not implemented DomainKeys in my mail servers (but they was in the past), but I noticed that my DNS servers was wrong configured to support this protocol. DomainKeys needs two TXT records, one for the policy and one for the selector.

The policy is set with a TXT record for, “o=~;” means that some mails can be signed and “o=-;” means all mails must be signed for domain I my case I had to change “o=-;” to “o=~;” because now, I was not using Domainkeys in my MTAs.

_domainkey                TXT    "o=~;"

The selector is implemented with other TXT record, in which you set your public key. According to RFC:

Selectors are arbitrary names below the “_domainkey.” namespace. A selector value
and length MUST be legal in the DNS namespace and in email headers
with the additional provision that they cannot contain a semicolon.

brisbane._domainkey IN TXT "g=; k=rsa; p=MHww ... IDAQAB"

The flags you can set are explained below:

g = granularity of the key. If present with a non-zero length
value, this value MUST exactly match the local part of the
sending address. This tag is optional.

The intent of this tag is to constrain which sending address
can legitimately use this selector. An email with a sending
address that does not match the value of this tag constitutes
a failed verification.

k = key type (rsa is the default). Signers and verifiers MUST
support the ‘rsa’ key type. This tag is optional.

n = Notes that may be of interest to a human. No interpretation
is made by any program. This tag is optional.

p = public key data, encoded as a Base64 string. An empty value
means that this public key has been revoked. This tag MUST be

t = a set of flags that define boolean attributes. Valid
attributes are as follows:

y = testing mode. This domain is testing DomainKeys and
unverified email MUST NOT be treated differently from
verified email. Recipient systems MAY wish to track
testing mode results to assist the sender.

This tag is optional.

For example, valid entries for selectors can be:


Here, you can use these links to test if your DNS records are well formed. the first one is to check your policy and the last one to check the selector: