So, really, this is just a log of what I’ve done, as I could not find this info anywhere in either the wiki or the forums. Maybe my google-fu wasn’t the best, but, I have all green checks on a received message, so that’s good.


  • It’s beyond the scope of this little document to explain how these things work. There are a ton of resources available online.


  • You are running the freepbx distro
  • Your pbx has a routable IP (there are ways around this, you can totally send mail without one, but RDNS can get interesting this way. It also usually implies your behind someone else’s NAT, and getting any of the big ISPs to publish RDNS can be fun)
  • You are sending mail from freepbx (not through another SMTP relay - particularly if you are just sending through a gmail account, they take care of most of this for you)
  • You have set up DNS and RDNS (RDNS is critical for SPF)


No on site config is necessary, assuming you have set DNS and RDNS appropriately, add an a: record to your existing SPF. i.e.

mydomain.com. TXT "v=spf1 a:freepbx.mydomain.com include:_spf.google.com ~all"

In my case, I use google domain apps for most of my email.


You’ll need CLI access for this.

$ yum install opendkim

$ cd /etc/opendkim/keys

mydomain should be your domain, myselector can be any alpha-numeric string. I used freepbx.

$ opendkim-genkey -d mydomain.com -s myselector

Don’t forget to change the ownership of the private key, or opendkim will not start

$ chown opendkim:opendkim myselector.private

/etc/opendkim.conf CHANGES

$ vim /etc/opendkim.conf
##  Selects operating modes. Valid modes are s (sign) and v (verify). Default is v.
##  Must be changed to s (sign only) or sv (sign and verify) in order to sign outgoing
##  messages.
Mode    sv

##  Create a socket through which your MTA can communicate.
Socket  inet:[email protected]

##  Selects the canonicalization method(s) to be used when signing messages.
Canonicalization        relaxed/simple

##  Domain(s) whose mail should be signed by this filter. Mail from other domains will
##  be verified rather than being signed. Uncomment and use your domain name.
##  This parameter is not required if a SigningTable is in use.
Domain  mydomain.com

##  Defines the name of the selector to be used when signing messages.
Selector        myselector

##  Gives the location of a private key to be used for signing ALL messages. This
##  directive is ignored if KeyTable is enabled.
KeyFile /etc/opendkim/keys/myselector.private

/etc/postfix/main.cf ADDITIONS

Put these all the way at the bottom. If for some reason you changed the listening host or port of the socket, make sure you reflect that here (for some reason an ubuntu install I have used a different port - make sure to match them)

$ vim /etc/postfix/main.cf
smtpd_milters = inet:
non_smtpd_milters = $smtpd_milters
milter_default_action = accept

Add the DNS record

You will like your life better if you add the DNS TXT record before sending your first test, as most of the big email services cache the results for a good while. The full record is located in:

$ cat /etc/opendkim/keys/myselector.txt

It’s an exercise for the reader to understand how to update their DNS records, reload and propegate them. But you can check that it is in there with something like:

$ dig -t txt myselector._domainkey.mydomain.com @

Start and enable opendkim, restart postfix:

$ systemctl start opendkim ; systemctl enable opendkim ; systemctl restart postfix

If everything is working, you’ll see something like this in /var/log/maillog:

OpenDKIM starting…

Oct  7 10:30:19 freepbx opendkim[3642]: OpenDKIM Filter v2.11.0 starting (args: -x /etc/opendkim.conf -P /var/run/opendkim/opendkim.pid)

OpenDKIM signing a message:

Oct  7 10:32:15 freepbx opendkim[3642]: 754A6602F3B0: DKIM-Signature field added (s=myselector, d=mydomain.com)

If it works, and you have gmail, clicking on “show original” will give you the SPF / DKIM / DMARC results. A “good” result looks something like this, pardon the redactions.


This document doesn’t really touch on how this bit works - there are too many much better resources out there that do a far better job than I could, and it does not require anything done on the freepbx system itself.

Questions / Comments

I welcome any questions or comments, but this is really meant to be a log of what I did to get this to work - I am by no means an expert - for specific error messages, I suspect google will be more useful than I will be, but I’ll do my best as I can.


Nice write-up! Maybe @lgaetz or @dolesec could enable your account on the wiki to contribute it there.

Good candidate for the Community Doc project:

1 Like

Good call.


The only bit I couldn’t do was upload the single image - it’s on imgur for the time being if anyone with access wants to shift it over, or if imgur is good for long term.

[image uploaded - mod]


This topic was automatically closed 31 days after the last reply. New replies are no longer allowed.