<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>clamav &#8211; Blog of Kliment Andreev &#8211; A place so I won&#039;t forget things</title>
	<atom:link href="https://blog.andreev.it/tag/clamav/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.andreev.it</link>
	<description></description>
	<lastBuildDate>Sat, 24 Oct 2020 13:12:21 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	
	<item>
		<title>CentOS: postfix, dovecot, Roundcube, amavisd-new, spamassassin, clamav on CentOS 7</title>
		<link>https://blog.andreev.it/2015/06/centos-7-postfix-dovecot-roundcube-amavisd-new-spamassassin-clamav-pigeonhole/</link>
					<comments>https://blog.andreev.it/2015/06/centos-7-postfix-dovecot-roundcube-amavisd-new-spamassassin-clamav-pigeonhole/#comments</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Thu, 04 Jun 2015 16:14:47 +0000</pubDate>
				<category><![CDATA[CentOS]]></category>
		<category><![CDATA[amavisd-new]]></category>
		<category><![CDATA[centos]]></category>
		<category><![CDATA[clamav]]></category>
		<category><![CDATA[dovecot]]></category>
		<category><![CDATA[postfix]]></category>
		<category><![CDATA[Roundcube]]></category>
		<category><![CDATA[spamassassin]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=1975</guid>

					<description><![CDATA[In one of my previous posts I&#8217;ve described how to run a postfix and&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>In one of my previous <a href="https://blog.andreev.it/?p=849" target="_blank" rel="noopener noreferrer">posts</a> I&#8217;ve described how to run a postfix and dovecot on CentOS 6. This time, we&#8217;ll go a step further and after the installation of <a href="http://www.postfix.org/" target="_blank" rel="noopener noreferrer">postfix</a> and <a href="http://www.dovecot.org/" target="_blank" rel="noopener noreferrer">dovecot</a>, we&#8217;ll talk about mail filtering, spam and anti-virus protection. </p>
<h1>Pre install</h1>
<p>The post described below uses:</p>
<ul>
<li> CentOS 7.1.1503 (fresh install)</li>
<li> Kernel 3.10.0-229.4.2.e17.x86_64
<li> postfix 2.10.1
<li> dovecot 2.2.10
<li> amavisd-new 2.10.1
<li> spamassasin 3.4.0
<li> clamav 0.98.7
<li> pigeonhole 0.4.3</li>
</ul>
<p>and will allow you to use virtual e-mail domains and users.</p>
<h1>postfix</h1>
<p>CentOS 7 comes with postfix preinstalled, so there is no need to install it first. Verify that postfix is installed and enabled to run on boot.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
systemctl status postfix | grep enabled
   Loaded: loaded (/usr/lib/systemd/system/postfix.service; enabled)
</pre>
<p><strong>NOTE: Highlighted numbers are what you type. The rest is the response from the server.</strong></p>
<p>The configuration files for postfix are in <strong>/etc/postfix</strong>. There are two main files, <strong>main.cf</strong> and <strong>master.cf</strong>. Make a copy of both these files.</p>
<pre class="brush: bash; title: ; notranslate">
cd /etc/postfix
cp main.cf main.cf.ORIG
cp master.cf master.cf.ORIG
</pre>
<p>On CentOS postfix also comes with a postfix username and postfix group that are used to run the daemon, but we&#8217;ll need a separate user and group. Technically we can use postfix user but it&#8217;s not recommended to use any UID that&#8217;s lower than 500. So, let&#8217;s create a new user and a group.</p>
<pre class="brush: bash; title: ; notranslate">
groupadd vpostfix &amp;&amp; useradd vpostfix -g vpostfix -s /sbin/nologin -c &quot;Virtual postfix user&quot; -d /var/empty
</pre>
<p>Ignore the warning that the home directory exists, that&#8217;s fine.<br />
Get the UID and GID because we will need these numbers for the configuration. </p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
grep vpostfix /etc/passwd &amp;&amp; grep vpostfix /etc/group
vpostfix:x:1001:1001:Virtual postfix user:/var/empty:/sbin/nologin
vpostfix:x:1001:
</pre>
<p>In my case the output was this, which means the <strong>UID is 1001</strong> and <strong>GID is 1001</strong>.<br />
Now, edit <strong>main.cf</strong> and change the following values:</p>
<pre class="brush: bash; title: ; notranslate">
myhostname = www.example.com
mydomain = example.com
myorigin = $mydomain
inet_interfaces = all
home_mailbox = Maildir/
</pre>
<p>Replace <strong>www.example.com</strong> with whatever your FQDN of the server is. Also, note that by default <strong>inet_interfaces = localhost</strong> is enabled by default. You have to comment this line. We will also use Maildir format instead of mbox because it&#8217;s much better.<br />
While editing <strong>main.cf</strong>, add these lines at the end of the file. Make sure you replace UID and GID. Don&#8217;t just blindly copy &#038; paste.</p>
<pre class="brush: bash; title: ; notranslate">
# Virtual domain config
virtual_mailbox_domains = /etc/postfix/virtual_domains
virtual_mailbox_base = /var/mail/vhosts
virtual_mailbox_maps = hash:/etc/postfix/vmailbox
# Make sure you replace these UID:GID numbers
virtual_minimum_uid = 1001
virtual_uid_maps = static:1001
virtual_gid_maps = static:1001
virtual_alias_maps = hash:/etc/postfix/virtual
</pre>
<p>Now, create a new file called <strong>/etc/postfix/virtual_domains</strong>. This is the file where all of your domains will be listed. Of course, you’ll have to make sure that MX records of your domains point to the IP of the CentOS box.</p>
<pre class="brush: bash; title: ; notranslate">
cd /etc/postfix/
touch virtual_domains
</pre>
<p>The format looks like this.</p>
<pre class="brush: bash; gutter: false; title: ; notranslate">
#  Put each domain in a separate line.
domain-one.com
domain-two.net
domain-three.org
</pre>
<p>Create the mail directory, sub-directories for the domains and assign the proper permissions. This is where the mail will be stored for all virtual domains.</p>
<pre class="brush: bash; title: ; notranslate">
mkdir /var/mail/vhosts
chgrp -R vpostfix /var/mail
cd /var/mail/vhosts
mkdir domain-one.com
mkdir domain-two.net
mkdir domain-three.org
cd ..
chown -R vpostfix:vpostfix vhosts
</pre>
<p>Once you do that, postfix will create the <strong>“Maildir”</strong> directories automatically and assign the proper permissions once an e-mail hits these destinations. Finally, create a file <strong>/etc/postfix/vmailbox</strong> and add all of the users that will receive e-mails. Here is an example:</p>
<pre class="brush: plain; gutter: false; title: ; notranslate">
joe@domain-one.com        domain-one.com/joe/
bill@domain-one.com       domain-one.com/bill/
@domain-one.com           domain-one.com/catch-all/
joe@domain-two.net        domain-two.net/joe/
</pre>
<p><strong>NOTE: Make sure you end up each line with “/”, otherwise mail won’t be delivered.</strong></p>
<p>Virtual user “joe@domain-one.com” (mind that there is no CentOS login for this user, these are all virtual users) will have his email delivered under <strong>/var/mail/vhosts/domain-one.com/joe</strong> directory. You don’t have to create these sub-directories. Once everything is up and running, postfix will take care of creating the Maildir structure (cur, new, tmp).</p>
<p>If you want you can create a <strong>catch-all</strong> address, see the example above (<strong>catch-all</strong>). This line tells postfix to get all the emails for the non-existing users in that domain (domain-one.com), which means a lot of spam. This is definitely not a recommended practice.</p>
<p>But what if you have a valid CentOS user named bill? Where that email goes? In this case, nowhere. If we want this OS user to receive an email, we’ll have to treat him as a virtual user and add him to a virtual domain. It’s much easier to maintain one list of virtual users and hosts than deal with separate configuration files.</p>
<p>Maybe you’ve noticed that the file with the e-mail addresses (vmailbox) has a <strong>hash:</strong> prefix in the config file. This is to speed-up lookups. Postfix can use <strong>hash:</strong> (Berkeley-DB), mySQL or PostgreSQL databases to store the e-mail accounts. Check the postfix howto if you want to use mySQL or PostgreSQL. We’ll be dealing with Berkeley DB.</p>
<p>Create the virtual aliases file and create a local aliases file.</p>
<pre class="brush: bash; title: ; notranslate">
touch /etc/postfix/virtual
cd /etc
postalias aliases
</pre>
<p>Once we are done with editing these files, do the following to create the hashed files (extension .db). </p>
<p><strong>NOTE: You should execute these lines anytime you make a change to these files (virtual_domains and vmailbox).</strong></p>
<pre class="brush: bash; title: ; notranslate">
postmap /etc/postfix/virtual
postmap /etc/postfix/vmailbox
</pre>
<p>At this point you can restart postfix so all changes that we made will take effect.:</p>
<pre class="brush: bash; title: ; notranslate">
systemctl restart postfix
</pre>
<p>Check the log file with:</p>
<pre class="brush: bash; title: ; notranslate">
tail /var/log/maillog
</pre>
<p>You should see that the daemon is started.</p>
<p>Check if postfix runs and listens on port 25.</p>
<pre class="brush: bash; highlight: [1,8]; title: ; notranslate">
ps -eaf | grep postfix
root      1627     1  0 Jun01 ?        00:00:00 /usr/libexec/postfix/master -w
postfix   1647  1627  0 Jun01 ?        00:00:00 qmgr -l -t unix -u
postfix  19407  1627  0 10:53 ?        00:00:00 pickup -l -t unix -u
postfix  19853  1627  0 12:05 ?        00:00:00 smtpd -n smtp -t inet -u -s 2
postfix  19854  1627  0 12:05 ?        00:00:00 proxymap -t unix -u
root     19862 19748  0 12:06 pts/0    00:00:00 grep --color=auto postfix
ss -l | grep smtp
u_str  LISTEN     0      100       private/smtp 14560                 * 0
tcp    LISTEN     0      100          127.0.0.1:smtp                  *:*
tcp    LISTEN     0      100                ::1:smtp                 :::*
</pre>
<p><strong>NOTE: </strong>You can stop and restart postfix with <strong>systemctl start postfix</strong> and <strong>systemctl stop postfix</strong> or reload the configuration files with <strong>systemctl reload postfix</strong>. </p>
<p>From another domain (e.g. your hotmail or gmail account) send an e-mail to joe@domain-one.com or whatever your domain is and watch the log file.</p>
<pre class="brush: bash; title: ; notranslate">
tail -f /var/log/maillog
</pre>
<p>You should see something like this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2015/06/P056-01.png"><img fetchpriority="high" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2015/06/P056-01.png" alt="" width="645" height="273" class="aligncenter size-full wp-image-7393" srcset="https://blog.andreev.it/wp-content/uploads/2015/06/P056-01.png 645w, https://blog.andreev.it/wp-content/uploads/2015/06/P056-01-300x127.png 300w, https://blog.andreev.it/wp-content/uploads/2015/06/P056-01-585x248.png 585w" sizes="(max-width: 645px) 100vw, 645px" /></a><br />
If you don&#8217;t see anything in the log and you verified that postfix is listening on port 25 from the server itself, most likely it&#8217;s a firewall issue. Open the SMTP port.</p>
<pre class="brush: bash; highlight: [1,3]; title: ; notranslate">
firewall-cmd --add-service=smtp --permanent
success
firewall-cmd --reload
success
</pre>
<p>If you check <strong>/var/mail/vhosts/domain-one/joe/new</strong> directory you’ll see a file with some gibberish name. This is your e-mail that you just sent to joe. But, how will this virtual user retrieve this e-mail? There is a login (the e-mail address), but what’s the password? </p>
<h1>dovecot</h1>
<p>In order to retrieve the e-mails, we’ll configure dovecot. Dovecot is an open-source POP and IMAP client.<br />
As of version 2.0, there are multiple configuration files for dovecot. The main file is <strong>/etc/dovecot/dovecot.conf</strong>, but you’ll see a lot of include directives there that point to <strong>/etc/dovecot/conf.d</strong> directory where we have multiple configuration files. CentOS doesn&#8217;t come up with dovecot installed, so we have to install it first.</p>
<pre class="brush: bash; title: ; notranslate">
yum install dovecot
</pre>
<p>Make a copy of <strong>/etc/dovecot/dovecot.conf</strong> and remove the comment from this line.</p>
<pre class="brush: bash; title: ; notranslate">
protocols = imap pop3 lmtp
</pre>
<p>Then, go to <strong>conf.d </strong>directory and change the following lines in the following files.</p>
<p><strong>10-auth.conf</strong></p>
<pre class="brush: bash; title: ; notranslate">
disable_plaintext_auth = no
#!include auth-system.conf.ext
!include auth-passwdfile.conf.ext
</pre>
<p><strong>10-logging.conf</strong></p>
<pre class="brush: bash; title: ; notranslate">
log_path = /var/log/dovecot.log
auth_verbose = no
auth_debug = no
verbose_ssl = no
</pre>
<p><strong>10-mail.conf</strong></p>
<pre class="brush: bash; title: ; notranslate">
mail_home = /var/mail/vhosts/%d/%n
mail_location = maildir:~
mail_uid = 1001    # These are the GID and UID numbers for postfix
mail_gid = 1001    # Don't just put random numbers here. Check above.
mail_privileged_group = vpostfix
</pre>
<p><strong>10-master.conf</strong></p>
<pre class="brush: bash; title: ; notranslate">
unix_listener auth-userdb {
  mode = 0600
  user = vpostfix
  group =  vpostfix
}
# Postfix smtp-auth
unix_listener /var/spool/postfix/private/auth {
  mode = 0666
  user = vpostfix
  group = vpostfix
}
</pre>
<p><strong>10-ssl.conf</strong></p>
<pre class="brush: bash; title: ; notranslate">
ssl = no
# ssl_cert = &lt;/etc/ssl/certs/dovecot.pem
# ssl_key = &lt;/etc/ssl/private/dovecot.pem
</pre>
<p>If you look at <strong>10-auth.conf</strong>, we commented the line <strong>#!include auth-system.conf.ext</strong> and uncommented the <strong>!include auth-passwdfile.conf.ext</strong>. Take a look at this file (<strong>auth-passwdfile.conf.ext</strong>) and you’ll see:</p>
<pre class="brush: bash; title: ; notranslate">
passdb {
  driver = passwd-file
  args = scheme=CRYPT username_format=%u /etc/dovecot/users
}
 
userdb {
  driver = passwd-file
  args = username_format=%u /etc/dovecot/users
}
</pre>
<p>This tells us that our username/password database will be in the file <strong>/etc/dovecot/users</strong>. To generate a password with SHA512-CRYPT password scheme do:</p>
<pre class="brush: bash; title: ; notranslate">
doveadm pw -s SHA512-CRYPT
</pre>
<p>You’ll be prompted to enter a password twice and the output will be similar to this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2015/06/P056-02.png"><img decoding="async" src="https://blog.andreev.it/wp-content/uploads/2015/06/P056-02.png" alt="" width="647" height="100" class="aligncenter size-full wp-image-7394" srcset="https://blog.andreev.it/wp-content/uploads/2015/06/P056-02.png 647w, https://blog.andreev.it/wp-content/uploads/2015/06/P056-02-300x46.png 300w, https://blog.andreev.it/wp-content/uploads/2015/06/P056-02-585x90.png 585w, https://blog.andreev.it/wp-content/uploads/2015/06/P056-02-640x100.png 640w" sizes="(max-width: 647px) 100vw, 647px" /></a><br />
If you want to use a different password scheme, take a look at this <a href="http://wiki2.dovecot.org/Authentication/PasswordSchemes" target="_blank" rel="noopener noreferrer">link</a>.<br />
Now, create or open <strong>/etc/dovecot/users</strong> and copy and paste the password after the username. In my case, I have <strong>joe@domain-one.com</strong> with some password that I just generated. So the line will be like this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2015/06/P056-03.png"><img decoding="async" src="https://blog.andreev.it/wp-content/uploads/2015/06/P056-03.png" alt="" width="643" height="43" class="aligncenter size-full wp-image-7395" srcset="https://blog.andreev.it/wp-content/uploads/2015/06/P056-03.png 643w, https://blog.andreev.it/wp-content/uploads/2015/06/P056-03-300x20.png 300w, https://blog.andreev.it/wp-content/uploads/2015/06/P056-03-585x39.png 585w, https://blog.andreev.it/wp-content/uploads/2015/06/P056-03-640x43.png 640w" sizes="(max-width: 643px) 100vw, 643px" /></a><br />
Don’t forget to add 4 colons after the password <strong>“::::”</strong>. Even if you use the same password for the users, they’ll be encrypted differently.</p>
<p>The problem with this scenario is that the end users won’t have the ability to change their passwords. So, you’ll have to provide them with the password and they won’t be able to reset them. But, there are plenty of perl scripts that can take care of this or you can write your own.</p>
<p>Start dovecot, enable it to start on boot and check for any errors. At this point, we should have dovecot running and listening for pop and imap connections. </p>
<pre class="brush: bash; title: ; notranslate">
systemctl start dovecot
systemctl enable dovecot
tail /var/log/dovecot.log
ss -l | grep pop3
ss -l | grep imap
</pre>
<p>Now, let’s check our e-mail. You can do that from the server using the telnet command.</p>
<p><strong>NOTE: Highlighted numbers are what you type. The rest is the response from the server. </strong></p>
<pre class="brush: bash; highlight: [1,6,8,10,12,17]; title: ; notranslate">
telnet localhost 110
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
+OK Dovecot ready.
user joe@domain-one.com
+OK
pass topsecret
+OK Logged in.
stat
+OK 2 2037
list
+OK 2 messages:
1 1027
2 1010
.
quit
+OK Logging out.
Connection closed by foreign host.
</pre>
<p>In the above example, I am testing POP3. For IMAP, do the following.</p>
<pre class="brush: bash; highlight: [1,6,8,11]; title: ; notranslate">
telnet localhost 143
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
* OK &#x5B;CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE AUTH=PLAIN] Dovecot ready.
? login joe@domain-one.com topsecret
? OK &#x5B;CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS SPECIAL-USE BINARY MOVE] Logged in
? list &quot;&quot; &quot;*&quot;
* LIST (\HasNoChildren) &quot;.&quot; INBOX
? OK List completed.
? logout
* BYE Logging out
? OK Logout completed.
Connection closed by foreign host.
</pre>
<p>If you want you can test retrieving these emails from a mail client such as Outlook, Opera Mail or any MUA of your preference. At this point the server can receive e-mails from others and you can retrieve those e-mails from outside using POP and IMAP. What we need to do now is to be able to reply to those e-mails from outside (using MUA of your choice). Nowadays port 25 is blocked at some major providers (Verizon, Comcast for example), so we’ll use SASL in Postfix and we’ll use Dovecot to authenticate the users using the same username/password combination. In addition, we’ll use certificates, so instead of POP3 and IMAP, we’ll use their secure equivalents, POP3s and IMAPs running on ports 995 and 993 respectively. At this point you can open ports 993 and 995 if you want and close 110 and 143 on the firewall. We won&#8217;t be using these ports (POP3 and IMAP).</p>
<h1>postfix and TLS</h1>
<p>Edit <strong>/etc/postfix/main.cf</strong> and add the following lines at the end.</p>
<pre class="brush: bash; title: ; notranslate">
# TLS
smtpd_use_tls = yes
smtpd_tls_security_level = may
smtpd_tls_auth_only = yes
smtpd_tls_key_file = /etc/postfix/myserver.key
smtpd_tls_cert_file = /etc/postfix/server.crt
smtpd_tls_loglevel = 1
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
tls_random_source = dev:/dev/urandom
 
# SASL
smtpd_sasl_type = dovecot
broken_sasl_auth_clients = yes
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination
smtpd_relay_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination
</pre>
<p><strong>NOTE: </strong>As of postfix 2.10 the last line is needed. See this <a href="http://www.postfix.org/SMTPD_ACCESS_README.html" target="_blank" rel="noopener noreferrer">link</a>.<br />
Then, edit <strong>/etc/postfix/master.cf</strong> and remove the comments from the submission part. </p>
<pre class="brush: bash; title: ; notranslate">
submission inet n       -       n       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_reject_unlisted_recipient=no
#  -o smtpd_client_restrictions=$mua_client_restrictions
#  -o smtpd_helo_restrictions=$mua_helo_restrictions
#  -o smtpd_sender_restrictions=$mua_sender_restrictions
  -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
  -o milter_macro_daemon_name=ORIGINATING
</pre>
<p>Restart postfix after these changes. </p>
<pre class="brush: bash; title: ; notranslate">
systemctl restart postfix
</pre>
<p>For information of what these values mean, check the links at the end of this post. If you do</p>
<pre class="brush: bash; title: ; notranslate">
ss -l | grep submission
grep submission /etc/services
</pre>
<p>you’ll see that postfix is also listening on port 587. Allow this port on the firewall if you don&#8217;t have it enabled, but don’t close port 25. This port is used for server to server communication. </p>
<pre class="brush: bash; title: ; notranslate">
firewall-cmd --add-port=587/tcp
firewall-cmd --reload
</pre>
<p>If you do <strong>telnet localhost 587</strong> and type <strong>EHLO something.com</strong> you should see that postfix replies with STARTTLS.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
telnet localhost 587
Trying ::1...
Connected to localhost.
Escape character is '^]'.
220 master.iandreev.us ESMTP Postfix
EHLO asdf.com
250-master.iandreev.us
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
</pre>
<p>Exit by pressing <strong>CTRL-]</strong> and then type quit.</p>
<h1>dovecot and SSL</h1>
<p>Edit <strong>10-auth.conf</strong> and change:</p>
<pre class="brush: bash; title: ; notranslate">
disable_plaintext_auth = yes
</pre>
<p>Then, edit <strong>10-ssl.conf</strong> and change:</p>
<pre class="brush: bash; title: ; notranslate">
ssl = yes
ssl_cert = &lt;/etc/postfix/server.crt
ssl_key = &lt;/etc/postfix/myserver.key
</pre>
<p>We’ll use self-signed certificates, but check <a href="http://www.startssl.com" target="_blank" rel="noopener noreferrer">http://www.startssl.com</a> for free certificates. Self-signed certificates are fake, so you’ll get a prompt to accept a fake certificate when you try to send/receive an email, but the goal is to show you how to use them, not to be a 100% compliant.</p>
<p>Unlike virtual Apache domains, you don’t need multiple certificates for each virtual domain. </p>
<pre class="brush: bash; title: ; notranslate">
cd /etc/postfix
openssl genrsa -out myserver.key 1024
openssl req -new -key myserver.key -out myserver.csr
</pre>
<p>You have to answer some questions for the certificate request.</p>
<pre class="brush: plain; highlight: [8,9,10,11,13,14]; title: ; notranslate">
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) &#x5B;AU]:US
State or Province Name (full name) &#x5B;Some-State]:NJ
Locality Name (eg, city) &#x5B;]:Lawrenceville
Organization Name (eg, company) &#x5B;Internet Widgits Pty Ltd]:Joe's Plumbing
Organizational Unit Name (eg, section) &#x5B;]:
Common Name (e.g. server FQDN or YOUR name) &#x5B;]:www.domain-one.com
Email Address &#x5B;]:joe@domain-one.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password &#x5B;]:
An optional company name &#x5B;]:
</pre>
<p>Sign the certificate.</p>
<pre class="brush: bash; title: ; notranslate">
openssl x509 -req -days 3650 -in myserver.csr -signkey myserver.key -out server.crt
</pre>
<p>The certificate files should be under <strong>/etc/postfix</strong> now. Restart both postfix and dovecot.</p>
<pre class="brush: bash; title: ; notranslate">
systemctl restart postfix
systemctl restart dovecot
</pre>
<p>You can test SMTP SSL/TLS on submission port 587.</p>
<pre class="brush: bash; title: ; notranslate">
openssl s_client -starttls smtp -connect localhost:587
</pre>
<p>Then type <strong>ehlo something.com</strong> , hit ENTER and then <strong>mail from:joe@domain-one.com</strong>. If these steps work, you should be OK. To test SASL with postfix and dovecot, type:</p>
<pre class="brush: bash; title: ; notranslate">
doveadm auth test -a /var/spool/postfix/private/auth joe@domain-one.com secret
passdb: joe@domain-one.com auth succeeded
extra fields:
  user=joe@domain-one.com
</pre>
<p>If you want you can open the firewall for IMAPs and POP3s. </p>
<pre class="brush: bash; title: ; notranslate">
firewall-cmd --add-port=993/tcp
firewall-cmd --add-port=995/tcp
firewall-cmd --reload
</pre>
<p>At this point, you should be able to send e-mails from your favorite MUA, but you’ll have to make some changes in order to send and receive. For example, in Outlook, you should use these settings.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2015/06/P056-04.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2015/06/P056-04.png" alt="" width="381" height="179" class="aligncenter size-full wp-image-7396" srcset="https://blog.andreev.it/wp-content/uploads/2015/06/P056-04.png 381w, https://blog.andreev.it/wp-content/uploads/2015/06/P056-04-300x141.png 300w" sizes="(max-width: 381px) 100vw, 381px" /></a><br />
So, no more port 110 and 143. Instead use 995 for POP3s, 587 for SMPT (SASL) and 993 for IMAPs. The username is your e-mail address and the password is the one that you generated with <strong>doveadm pw</strong> command.</p>
<p>Mind that if you use a web client like Roundcube and Roundcube is installed on the server where postfix and dovecot reside, you don&#8217;t have to open any port except 25. </p>
<h1>Roundcube IMAP webmail client</h1>
<p>In order to send/receive e-mails using a web client, you can use Roundcube. Please follow these guides to install it. </p>
<p><a href="https://blog.andreev.it/?p=1962" target="_blank" rel="noopener noreferrer">CentOS 7: Install LAMP (Linux, Apache, MySQL, PHP) + WordPress</a><br />
<a href="https://blog.andreev.it/?p=2004" target="_blank" rel="noopener noreferrer">CentOS 7: Install RoundCube Web Mail Client</a></p>
<h1>Amavisd, Spamassassin and clamav</h1>
<p>This software trio is used to fight spam messages and e-mails with virus attachments. Amavisd is used as an interface between postfix as MTA (mail transfer agent) and the content checkers (spamassassin and clamav). Clamav and spamassassin will be installed automatically once you install amavisd-new.</p>
<pre class="brush: bash; title: ; notranslate">
yum install amavisd-new
yum install clamav-udpate
</pre>
<p>First, let&#8217;s configure amavisd. The configuration file is <strong>/etc/amavisd/amavisd.conf</strong>. Edit this file and make sure that these values are correct. </p>
<pre class="brush: bash; title: ; notranslate">
# @bypass_virus_checks_maps = (1);  # controls running of anti-virus code
# @bypass_spam_checks_maps  = (1);  # controls running of anti-spam code
# $bypass_decode_parts = 1;         # controls running of decoders&amp;dearchivers
$daemon_user  = 'amavis';     # (no default;  customary: vscan or amavis), -u
$daemon_group = 'amavis';     # (no default;  customary: vscan or amavis), -g
$mydomain = 'example.com';   # a convenient default for other settings (change it)
$MYHOME = '/var/spool/amavisd';   # a convenient default for other settings, -H (remove the comment in front)
@local_domains_maps = ( &#x5B;&quot;.$mydomain&quot;,&quot;myotherdomain.net&quot;] );  # list of all local domains. If you have multiple domains, add the here.
$myhostname = 'host.example.com';  # must be a fully-qualified domain name! (remove the comment in front)
</pre>
<p>There are a lot of changes that you can configure, but these are the basic ones. See the <a href="http://www.ijs.si/software/amavisd/" target="_blank" rel="noopener noreferrer">official page</a> for more information.<br />
Finally, let&#8217;s make sure that amavisd and clamav know about each other. Go to line 383 and see if this is correct (383G in vi). </p>
<div style="border:1px solid red; padding:16px;">
<p style="text-align:center;"><strong><span style="color:#800000;">NOTE ABOUT MEMORY</span> </strong></p>
<p>Clamav eats up a lot of memory. You won&#8217;t be able to run it on a server with less than 2GB RAM. If you feel comfortable, you can disable it. Don&#8217;t uncomment the lines below, remove the comment from # @bypass_virus_checks_maps = (1);  # controls running of anti-virus code and </p>
</div>
<pre class="brush: bash; title: ; notranslate">
# ### http://www.clamav.net/
&#x5B;'ClamAV-clamd',
  \&amp;ask_daemon, &#x5B;&quot;CONTSCAN {}\n&quot;, &quot;/var/run/clamav/clamd.sock.sock&quot;],
  qr/\bOK$/m, qr/\bFOUND$/m,
  qr/^.*?: (?!Infected Archive)(.*) FOUND$/m ],
# # NOTE: run clamd under the same user as amavisd - or run it under its own
# #   uid such as clamav, add user clamav to the amavis group, and then add
# #   AllowSupplementaryGroups to clamd.conf;
# # NOTE: match socket name (LocalSocket) in clamav.conf to the socket name in
# #   this entry; when running chrooted one may prefer a socket under $MYHOME.
</pre>
<p>Now, let&#8217;s tie everything together with postfix. Edit <strong>/etc/postfix/master.cf</strong> and add these lines at the end.</p>
<pre class="brush: bash; title: ; notranslate">
# Amavisd
amavisfeed unix - - n - 2 lmtp
        -o lmtp_data_done_timeout=1200
        -o lmtp_send_xforward_command=yes
127.0.0.1:10025 inet n - n - - smtpd
        -o content_filter=
        -o smtpd_delay_reject=no
        -o smtpd_client_restrictions=permit_mynetworks,reject
        -o smtpd_helo_restrictions=
        -o smtpd_sender_restrictions=
        -o smtpd_recipient_restrictions=permit_mynetworks,reject
        -o smtpd_data_restrictions=reject_unauth_pipelining
        -o smtpd_end_of_data_restrictions=
        -o smtpd_restriction_classes=
        -o mynetworks=127.0.0.0/8
        -o smtpd_error_sleep_time=0
        -o smtpd_soft_error_limit=1001
        -o smtpd_hard_error_limit=1000
        -o smtpd_client_connection_count_limit=0
        -o smtpd_client_connection_rate_limit=0
        -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_milters,no_address_mappings
        -o local_header_rewrite_clients=
        -o smtpd_milters=
        -o local_recipient_maps=
        -o relay_recipient_maps=
</pre>
<p>Edit <strong>/usr/local/etc/postfix/main.cf</strong> and add these lines at the end.</p>
<pre class="brush: bash; title: ; notranslate">
# Amavisd
content_filter = amavisfeed:&#x5B;127.0.0.1]:10024
</pre>
<p>Before we start these three daemons, let&#8217;s make some changes. First, edit <strong>/etc/freshclam.conf</strong> and remove or comment the <strong>Example </strong>line. </p>
<pre class="brush: bash; title: ; notranslate">
# Comment or remove the line below.
Example
</pre>
<p>Then, edit <strong>/etc/sysconfig/freshclam </strong>and remove all 4 lines at the bottom.</p>
<pre class="brush: bash; title: ; notranslate">
### !!!!! REMOVE ME !!!!!!
### REMOVE ME: By default, the freshclam update is disabled to avoid
### REMOVE ME: network access without prior activation
FRESHCLAM_DELAY=disabled-warn   # REMOVE ME
</pre>
<p>Once you do that, update the antivirus definitions by executing:</p>
<pre class="brush: bash; title: ; notranslate">
freshclam
</pre>
<p>Then update spamassassins&#8217;s signatures.</p>
<pre class="brush: bash; title: ; notranslate">
sa-update -D
</pre>
<p>The &#8220;-D&#8221; option is to run in debug mode so you can see what&#8217;s going on. If there is an update available, spamassassin&#8217;s exit code is 0, if not the exit code is 1. In case there is an update, we&#8217;ll have to restart the spamassassin&#8217;s daemon.<br />
Check the cron folder and make sure you see both calamav-update and sa-update files. </p>
<pre class="brush: bash; title: ; notranslate">
cd /etc/cron.d
ls -l clamav-update sa-update
</pre>
<p>Now, we can start everything.</p>
<pre class="brush: bash; title: ; notranslate">
systemctl start amavisd
systemctl enable amavisd
systemctl start spamassassin
systemctl enable spamassassin
</pre>
<p>Once you start amavisd, clamd starts as well.<br />
Finally, let&#8217;s restart postfix.</p>
<pre class="brush: bash; title: ; notranslate">
systemctl restart postfix
</pre>
<p>Check the connection between amavisd and postfix.</p>
<pre class="brush: bash; title: ; notranslate">
telnet localhost 10024
</pre>
<p>Type <strong>ehlo localhost</strong> and check the ouput. In my case it looks like this.</p>
<pre class="brush: bash; gutter: false; title: ; notranslate">
250-&#x5B;127.0.0.1]
250-VRFY
250-PIPELINING
250-SIZE
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250 XFORWARD NAME ADDR PORT PROTO HELO IDENT SOURCE
</pre>
<p>Then do.</p>
<pre class="brush: bash; title: ; notranslate">
telnet localhost 10025
</pre>
<p>Again, type <strong>ehlo localhost</strong> and check the ouput. In my case it looks like this.</p>
<pre class="brush: bash; gutter: false; title: ; notranslate">
250-www.testcloudserver.org
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
</pre>
<p>And finally, some real tests. First, check the mail log file.</p>
<pre class="brush: bash; title: ; notranslate">
tail -f /var/log/maillog
</pre>
<p>Then, from another e-mail account, send a text (not HTML) e-mail with this in the body.</p>
<pre class="brush: bash; gutter: false; title: ; notranslate">
X5O!P%@AP&#x5B;4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*
</pre>
<p>You should see something like this in the logs.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2015/06/P056-05.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2015/06/P056-05.jpg" alt="" width="809" height="206" class="aligncenter size-full wp-image-7397" srcset="https://blog.andreev.it/wp-content/uploads/2015/06/P056-05.jpg 809w, https://blog.andreev.it/wp-content/uploads/2015/06/P056-05-300x76.jpg 300w, https://blog.andreev.it/wp-content/uploads/2015/06/P056-05-768x196.jpg 768w, https://blog.andreev.it/wp-content/uploads/2015/06/P056-05-585x149.jpg 585w" sizes="(max-width: 809px) 100vw, 809px" /></a><br />
Leave the log file open and let&#8217;s send another test e-mail, same text format, but this time put this line in the body of the message.</p>
<pre class="brush: bash; gutter: false; title: ; notranslate">
XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X
</pre>
<p>You should see something like this in the log file.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2015/06/P056-06.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2015/06/P056-06.jpg" alt="" width="807" height="215" class="aligncenter size-full wp-image-7398" srcset="https://blog.andreev.it/wp-content/uploads/2015/06/P056-06.jpg 807w, https://blog.andreev.it/wp-content/uploads/2015/06/P056-06-300x80.jpg 300w, https://blog.andreev.it/wp-content/uploads/2015/06/P056-06-768x205.jpg 768w, https://blog.andreev.it/wp-content/uploads/2015/06/P056-06-585x156.jpg 585w" sizes="(max-width: 807px) 100vw, 807px" /></a></p>
<h1>Stress test</h1>
<p>From another server with postfix installed, do:</p>
<pre class="brush: bash; title: ; notranslate">
time /usr/sbin/smtp-source -s 40 -l 10120 -m 5000 -c -f user@whatsup.com -t joe@domain-one.com mail.domain-one.com:25
</pre>
<p>On your server do:</p>
<pre class="brush: bash; title: ; notranslate">
tail -f /var/log/maillog
</pre>
<p>Make sure that the server where you run <strong>smtp-source</strong> is a legit server, otherwise your postfix will just reject all messages.<br />
Watch how your log file gets bombarded with messages. You can also watch the queue real-time with:</p>
<pre class="brush: bash; title: ; notranslate">
postqueue -p
</pre>
<p>If you are satisfied with the results after 5-10 mins, empty the postfix queue with:</p>
<pre class="brush: bash; title: ; notranslate">
postsuper -d ALL
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2015/06/centos-7-postfix-dovecot-roundcube-amavisd-new-spamassassin-clamav-pigeonhole/feed/</wfw:commentRss>
			<slash:comments>9</slash:comments>
		
		
			</item>
		<item>
		<title>FreeBSD 10: postfix, dovecot, Roundcube, amavisd-new, spamassassin, clamav, pigeonhole</title>
		<link>https://blog.andreev.it/2014/11/freebsd-10-postfix-dovecot-amavisd-new-spamassassin-clamav-pigeonhole/</link>
					<comments>https://blog.andreev.it/2014/11/freebsd-10-postfix-dovecot-amavisd-new-spamassassin-clamav-pigeonhole/#comments</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Fri, 07 Nov 2014 20:39:49 +0000</pubDate>
				<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[amavisd-new]]></category>
		<category><![CDATA[clamav]]></category>
		<category><![CDATA[dovecot]]></category>
		<category><![CDATA[freebsd]]></category>
		<category><![CDATA[pigeonhole]]></category>
		<category><![CDATA[postfix]]></category>
		<category><![CDATA[Roundcube]]></category>
		<category><![CDATA[spamassassin]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=1604</guid>

					<description><![CDATA[In one of my previous posts I&#8217;ve described how to run a postfix and&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>In one of my previous <a href="https://blog.andreev.it/?p=936" target="_blank" rel="noopener noreferrer">posts</a> I&#8217;ve described how to run a postfix and dovecot servers on FreeBSD 9. This time, we&#8217;ll go a step further and after the installation of <a href="http://www.postfix.org/" target="_blank" rel="noopener noreferrer">postfix</a> and <a href="http://www.dovecot.org/" target="_blank" rel="noopener noreferrer">dovecot</a>, we&#8217;ll talk about mail filtering, spam and anti-virus protection. </p>
<h1>Pre install</h1>
<p>The post described below uses:</p>
<ul>
<li> FreeBSD 10.0-p12 (fresh install)</li>
<li> postfix 2.11.3
<li> dovecot 2.2.15
<li> amavisd-new 2.9.1
<li> spamassasin 3.4.0
<li> clamav 0.98.4
<li> pigeonhole 0.4.3</li>
</ul>
<p>and will allow you to use virtual e-mail domains and users.</p>
<p>FreeBSD comes with sendmail preinstalled, so we need to remove it first. Edit <strong>/etc/rc.conf</strong> and add these lines.</p>
<pre class="brush: bash; title: ; notranslate">
# Disable sendmail
sendmail_enable=&quot;NO&quot;
sendmail_submit_enable=&quot;NO&quot;
sendmail_outbound_enable=&quot;NO&quot;
sendmail_msp_queue_enable=&quot;NO&quot;
</pre>
<p>Then terminate all sendmail processes.</p>
<pre class="brush: bash; title: ; notranslate">
killall sendmail
</pre>
<h1>postfix</h1>
<p>We&#8217;ll install postfix from the ports. The packaged install doesn&#8217;t come up with some prerequisites.<br />
<strong>NOTE</strong>: Recently, I got an e-mail saying that if you install the postfix-sasl package, you don&#8217;t have to deal with the ports. Try <strong>pkg install postfix-sasl</strong> instead and see if it works. </p>
<pre class="brush: bash; title: ; notranslate">
cd /usr/ports/mail/postfix
make all install clean
</pre>
<p>Make sure that <strong>BDB, PCRE, TLS</strong> and <strong>DOVECOT2</strong> are selected and <strong>INST_BASE</strong> is not selected. <strong>OPTIONAL:</strong> Select <strong>TEST</strong> if you want to do a stress test (see below). I am using Berkeley DB as a back-end database. If you want to use MySQL or PostgreSQL, the scenario below won&#8217;t apply for postfix. The rest (dovecot, amavisd&#8230;) configs should be fine. </p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2014/11/P048-01.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2014/11/P048-01.png" alt="" width="665" height="421" class="aligncenter size-full wp-image-7153" srcset="https://blog.andreev.it/wp-content/uploads/2014/11/P048-01.png 665w, https://blog.andreev.it/wp-content/uploads/2014/11/P048-01-300x190.png 300w, https://blog.andreev.it/wp-content/uploads/2014/11/P048-01-585x370.png 585w" sizes="(max-width: 665px) 100vw, 665px" /></a><br />
<a href="https://blog.andreev.it/wp-content/uploads/2014/11/P048-02.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2014/11/P048-02.png" alt="" width="671" height="425" class="aligncenter size-full wp-image-7154" srcset="https://blog.andreev.it/wp-content/uploads/2014/11/P048-02.png 671w, https://blog.andreev.it/wp-content/uploads/2014/11/P048-02-300x190.png 300w, https://blog.andreev.it/wp-content/uploads/2014/11/P048-02-585x371.png 585w" sizes="(max-width: 671px) 100vw, 671px" /></a><br />
You should accept the defaults for <strong>perl5, pcre, db5, gmake, gettext</strong> and <strong>dovecot2</strong>. Once completed you&#8217;ll see this message.</p>
<pre class="brush: plain; gutter: false; title: ; notranslate">
Would you like to activate Postfix in /etc/mail/mailer.conf &#x5B;n]?
</pre>
<p>Say <strong>y</strong>, edit <strong>/etc/rc.conf</strong> and add these two lines to start <strong>postfix</strong> and <strong>dovecot</strong> automatically on boot.</p>
<pre class="brush: bash; title: ; notranslate">
postfix_enable=&quot;YES&quot;
dovecot_enable=&quot;YES&quot;
</pre>
<p>The configuration files for postfix are in <strong>/usr/local/etc/postfix</strong>. There are two main files, <strong>main.cf</strong> and <strong>master.cf</strong>. Make a copy of both these files.</p>
<pre class="brush: bash; title: ; notranslate">
cd /usr/local/etc/postfix
cp main.cf main.cf.ORIG
cp master.cf master.cf.ORIG
</pre>
<p>Create a user that will have access to the mailboxes and get its <strong>UID</strong> and <strong>GID</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
pw groupadd vpostfix &amp;&amp; pw useradd vpostfix -g vpostfix -s /usr/sbin/nologin -c &quot;Virtual Postfix user&quot; -d /var/empty
grep vpostfix /etc/passwd
</pre>
<p>In my case the output was this, which means the <strong>UID is 1002</strong> and <strong>GID is 1001</strong>.</p>
<pre class="brush: bash; gutter: false; title: ; notranslate">
vpostfix:*:1002:1001:Virtual Postfix user:/var/empty:/usr/sbin/nologin
</pre>
<p>Now, edit <strong>main.cf</strong> and change the following values:</p>
<pre class="brush: bash; title: ; notranslate">
myhostname = www.example.com
mydomain = example.com
myorigin = $mydomain
inet_interfaces = all
home_mailbox = Maildir/
</pre>
<p>Replace <strong>www.example.com</strong> with whatever your FQDN of the server is. While editing <strong>main.cf</strong>, add these lines at the end of the file.</p>
<pre class="brush: bash; title: ; notranslate">
# Virtual domain config
virtual_mailbox_domains = /usr/local/etc/postfix/virtual_domains
virtual_mailbox_base = /var/mail/vhosts
virtual_mailbox_maps = hash:/usr/local/etc/postfix/vmailbox
# Make sure you replace these UID:GID numbers
virtual_minimum_uid = 1002
virtual_uid_maps = static:1002
virtual_gid_maps = static:1001
virtual_alias_maps = hash:/usr/local/etc/postfix/virtual
</pre>
<p>Now, create a new file called <strong>/usr/local/etc/postfix/virtual_domains</strong>. This is the file where all of your domains will be listed. Of course, you’ll have to make sure that MX records of your domains point to the IP of the FreeBSD box.</p>
<pre class="brush: bash; title: ; notranslate">
cd /usr/local/etc/postfix/
touch virtual_domains
</pre>
<p>The format looks like this.</p>
<pre class="brush: bash; gutter: false; title: ; notranslate">
#  Put each domain in a separate line.
domain-one.com
domain-two.net
domain-three.org
</pre>
<p>Create the mail directory, sub-directories for the domains and assign the proper permissions. This is where the mail will be stored for all virtual domains.</p>
<pre class="brush: bash; title: ; notranslate">
mkdir /var/mail/vhosts
chgrp -R vpostfix /var/mail
cd /var/mail/vhosts
mkdir domain-one.com
mkdir domain-two.net
mkdir domain-three.org
cd ..
chown -R vpostfix:vpostfix vhosts
</pre>
<p>Once you do that, postfix will create the <strong>“Maildir”</strong> directories automatically and assign the proper permissions once an e-mail hits these destinations. Finally, create a file <strong>/usr/local/etc/postfix/vmailbox</strong> and add all of the users that will receive e-mails. Here is an example:</p>
<pre class="brush: plain; gutter: false; title: ; notranslate">
joe@domain-one.com        domain-one.com/joe/
bill@domain-one.com       domain-one.com/bill/
@domain-one.com           domain-one.com/catch-all/
joe@domain-two.net        domain-two.net/joe/
</pre>
<p><strong>NOTE: Make sure you end up each line with “/”, otherwise mail won’t be delivered.</strong></p>
<p>Virtual user “joe@domain-one.com” (mind that there is no FreeBSD login for this user, these are all virtual users) will have his email delivered under <strong>/var/mail/vhosts/domain-one.com/joe</strong> directory. You don’t have to create these sub-directories. Once everything is up and running, postfix will take care of creating the Maildir structure (cur, new, tmp).</p>
<p>If you want you can create a <strong>catch-all</strong> address, see the example above (<strong>catch-all</strong>). This line tells postfix to get all the emails for the non-existing users in that domain (domain-one.com), which means a lot of spam.</p>
<p>But what if you have a valid FreeBSD user named bill? Where that email goes? In this case, nowhere. If we want this OS user to receive an email, we’ll have to treat him as a virtual user and add him to a virtual domain. It’s much easier to maintain one list of virtual users and hosts than deal with separate configuration files.</p>
<p>Maybe you’ve noticed that the file with the e-mail addresses (vmailbox) has a <strong>hash:</strong> prefix in the config file. This is to speed-up lookups. Postfix can use <strong>hash:</strong> (Berkeley-DB), mySQL or PostgreSQL database to store the e-mail accounts. Check the postfix howto if you want to use mySQL or PostgreSQL. We’ll be dealing with Berkeley DB.</p>
<p>Create the virtual aliases file and create a local aliases file.</p>
<pre class="brush: bash; title: ; notranslate">
touch /usr/local/etc/postfix/virtual
cd /etc
postalias aliases
</pre>
<p>Once we are done with editing these files, do the following to create the hashed files (extension .db). </p>
<p><strong>NOTE: You should execute these lines anytime you make a change to these files.</strong></p>
<pre class="brush: bash; title: ; notranslate">
postmap /usr/local/etc/postfix/virtual
postmap /usr/local/etc/postfix/vmailbox
</pre>
<p>Postfix can be started with:</p>
<pre class="brush: bash; title: ; notranslate">
service postfix start
</pre>
<p>Check the log file with:</p>
<pre class="brush: bash; title: ; notranslate">
tail /var/log/maillog
</pre>
<p>In my case I saw these lines in the log file.</p>
<pre class="brush: plain; gutter: false; title: ; notranslate">
Nov  6 17:57:04 www postfix/postfix-script&#x5B;76814]: starting the Postfix mail system
Nov  6 17:57:04 www postfix/master&#x5B;76816]: daemon started -- version 2.11.3, configuration /usr/local/etc/postfix
</pre>
<p>Check if postfix runs and listens on port 25.</p>
<pre class="brush: bash; title: ; notranslate">
ps -waux | grep postfix
sockstat -4 | grep :25
</pre>
<p><strong>NOTE: </strong>You can stop and restart postfix with <strong>service postfix stop</strong> and <strong>service postfix restart</strong> or reload the configuration files with <strong>service postfix reload</strong>. </p>
<p>From another domain (e.g. your hotmail or gmail account) send an e-mail to joe@domain-one.com or whatever your domain is and watch the log file.</p>
<pre class="brush: bash; title: ; notranslate">
tail -f /var/log/maillog
</pre>
<p>You should see something like this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2014/11/P048-03.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2014/11/P048-03.png" alt="" width="726" height="250" class="aligncenter size-full wp-image-7155" srcset="https://blog.andreev.it/wp-content/uploads/2014/11/P048-03.png 726w, https://blog.andreev.it/wp-content/uploads/2014/11/P048-03-300x103.png 300w, https://blog.andreev.it/wp-content/uploads/2014/11/P048-03-585x201.png 585w" sizes="(max-width: 726px) 100vw, 726px" /></a></p>
<p>If you check <strong>/var/mail/vhosts/domain-one/joe/new</strong> directory you’ll see a file with some gibberish name. This is your e-mail that you just sent to joe. But, how will this virtual user retrieve this e-mail? There is a login (the e-mail address), but what’s the password? </p>
<h1>dovecot</h1>
<p>In order to retrieve the e-mails, we’ll configure dovecot. Dovecot is an open-source POP and IMAP client.<br />
As of version 2.0, there are multiple configuration files for dovecot. The main file is <strong>/usr/local/etc/dovecot/dovecot.conf</strong>, but you’ll see a lot of include directives there that point to <strong>/usr/local/etc/dovecot/conf.d</strong> directory where we have multiple configuration files. FreeBSD comes with these files under a different directory, so we’ll have to copy them to their proper location.</p>
<pre class="brush: bash; title: ; notranslate">
cd /usr/local/etc/dovecot
cp -R /usr/local/share/doc/dovecot/example-config/ .
</pre>
<p>Make a copy of <strong>dovecot.conf</strong> and remove the comment from this line.</p>
<pre class="brush: bash; title: ; notranslate">
protocols = imap pop3 lmtp
</pre>
<p>Then, go to <strong>conf.d </strong>directory and change the following lines in the following files.</p>
<p><strong>10-auth.conf</strong></p>
<pre class="brush: bash; title: ; notranslate">
disable_plaintext_auth = no
#!include auth-system.conf.ext
!include auth-passwdfile.conf.ext
</pre>
<p><strong>10-logging.conf</strong></p>
<pre class="brush: bash; title: ; notranslate">
log_path = /var/log/dovecot.log
auth_verbose = no
auth_debug = no
verbose_ssl = no
</pre>
<p><strong>10-mail.conf</strong></p>
<pre class="brush: bash; title: ; notranslate">
mail_home = /var/mail/vhosts/%d/%n
mail_location = maildir:~
mail_uid = 1002    # These are the GID and UID numbers for vpostfix
mail_gid = 1001    # Don't just put these numbers here
mail_privileged_group = vpostfix
</pre>
<p><strong>10-master.conf</strong></p>
<pre class="brush: bash; title: ; notranslate">
unix_listener auth-userdb {
  mode = 0600
  user = postfix
  group =  postfix
}
# Postfix smtp-auth
unix_listener /var/spool/postfix/private/auth {
  mode = 0666
  user = postfix
  group = postfix
}
</pre>
<p><strong>10-ssl.conf</strong></p>
<pre class="brush: bash; title: ; notranslate">
ssl = no
# ssl_cert = &lt;/etc/ssl/certs/dovecot.pem
# ssl_key = &lt;/etc/ssl/private/dovecot.pem
</pre>
<p>If you look at <strong>10-auth.conf</strong>, we commented the line <strong>#!include auth-system.conf.ext</strong> and uncommented the <strong>!include auth-passwdfile.conf.ext</strong>. Take a look at this file (<strong>auth-passwdfile.conf.ext</strong>) and you’ll see:</p>
<pre class="brush: bash; title: ; notranslate">
passdb {
  driver = passwd-file
  args = scheme=CRYPT username_format=%u /usr/local/etc/dovecot/users
}
 
userdb {
  driver = passwd-file
  args = username_format=%u /usr/local/etc/dovecot/users
}
</pre>
<p>This tells us that our username/password database will be in the file <strong>/usr/local/etc/dovecot/users</strong>. To generate a password with SHA512-CRYPT password scheme do:</p>
<pre class="brush: bash; title: ; notranslate">
doveadm pw -s SHA512-CRYPT
</pre>
<p>You’ll be prompted to enter a password twice and the output will be similar to this.</p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2014/11/P048-04.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2014/11/P048-04.png" alt="" width="726" height="141" class="aligncenter size-full wp-image-7156" srcset="https://blog.andreev.it/wp-content/uploads/2014/11/P048-04.png 726w, https://blog.andreev.it/wp-content/uploads/2014/11/P048-04-300x58.png 300w, https://blog.andreev.it/wp-content/uploads/2014/11/P048-04-585x114.png 585w" sizes="(max-width: 726px) 100vw, 726px" /></a><br />
If you want to use a different password scheme, take a look at this <a href="http://wiki2.dovecot.org/Authentication/PasswordSchemes" target="_blank" rel="noopener noreferrer">link</a>.<br />
Now, create or open <strong>/usr/local/etc/dovecot/users</strong> and copy and paste the password after the username. In my case, I have <strong>joe@domain-one.com</strong> with some password that I just generated. So the line will be like this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2014/11/P048-05.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2014/11/P048-05.png" alt="" width="728" height="97" class="aligncenter size-full wp-image-7157" srcset="https://blog.andreev.it/wp-content/uploads/2014/11/P048-05.png 728w, https://blog.andreev.it/wp-content/uploads/2014/11/P048-05-300x40.png 300w, https://blog.andreev.it/wp-content/uploads/2014/11/P048-05-585x78.png 585w" sizes="(max-width: 728px) 100vw, 728px" /></a><br />
Don’t forget to add 4 colons after the password <strong>“::::”</strong>. Even if you use the same password for the users, they’ll be encrypted differently.</p>
<p>The problem with this scenario is that the end users won’t have the ability to change their passwords. So, you’ll have to provide them with the password and they won’t be able to reset them. But, there are plenty of perl scripts that can take care of this or you can write your own.</p>
<p>Start dovecot and check for any errors. At this point, we should have dovecot running and listening for pop and imap connections. </p>
<pre class="brush: bash; title: ; notranslate">
service dovecot start
tail /var/log/dovecot.log
sockstat -4 | grep :110
sockstat -4 | grep :143
</pre>
<p>Now, let’s check our e-mail. You can do that from the server using the telnet command.</p>
<p><strong>NOTE: Highlighted numbers are what you type. The rest is the response from the server. </strong></p>
<pre class="brush: bash; highlight: [1,6,8,10,12,17]; title: ; notranslate">
telnet localhost 110
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
+OK Dovecot ready.
user joe@domain-one.com
+OK
pass topsecret
+OK Logged in.
stat
+OK 2 2037
list
+OK 2 messages:
1 1027
2 1010
.
quit
+OK Logging out.
Connection closed by foreign host.
</pre>
<p>In the above example, I am testing POP3. For IMAP, do the following.</p>
<pre class="brush: bash; highlight: [1,6,8,11]; title: ; notranslate">
telnet localhost 143
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
* OK &#x5B;CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE AUTH=PLAIN] Dovecot ready.
? login joe@domain-one.com topsecret
? OK &#x5B;CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS SPECIAL-USE BINARY MOVE] Logged in
? list &quot;&quot; &quot;*&quot;
* LIST (\HasNoChildren) &quot;.&quot; INBOX
? OK List completed.
? logout
* BYE Logging out
? OK Logout completed.
Connection closed by foreign host.
</pre>
<p>If you want you can test retrieving these emails from a mail client such as Outlook, Opera Mail or any MUA of your preference. At this point the server can receive e-mails from others and you can retrieve those e-mails from outside using POP and IMAP. What we need to do now is to be able to reply to those e-mails from outside (using MUA of your choice). Nowadays port 25 is blocked at some major providers (Verizon, Comcast for example), so we’ll use SASL in Postfix and we’ll use Dovecot to authenticate the users using the same username/password combination. In addition, we’ll use certificates, so instead of POP3 and IMAP, we’ll use their secure equivalents, POP3s and IMAPs running on ports 995 and 993 respectively. Dovecot should already listen on these ports, so you can allow these ports on the firewall and close 110 and 143. </p>
<h1>postfix and TLS</h1>
<p>Edit <strong>/usr/local/etc/postfix/main.cf</strong> and add the following lines at the end.</p>
<pre class="brush: bash; title: ; notranslate">
# TLS
smtpd_use_tls = yes
smtpd_tls_security_level = may
smtpd_tls_auth_only = yes
smtpd_tls_key_file = /usr/local/etc/postfix/myserver.key
smtpd_tls_cert_file = /usr/local/etc/postfix/server.crt
smtpd_tls_loglevel = 1
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
tls_random_source = dev:/dev/urandom
 
# SASL
smtpd_sasl_type = dovecot
broken_sasl_auth_clients = yes
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination
smtpd_relay_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination
</pre>
<p><strong>NOTE: </strong>As of postfix 2.10 the last line is needed. See this <a href="http://www.postfix.org/SMTPD_ACCESS_README.html" target="_blank" rel="noopener noreferrer">link</a>.<br />
Then, edit <strong>/usr/local/etc/postfix/master.cf</strong> and remove the comments from the submission part. </p>
<pre class="brush: bash; title: ; notranslate">
submission inet n       -       n       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_reject_unlisted_recipient=no
  -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
  -o milter_macro_daemon_name=ORIGINATING
</pre>
<p>Restart postfix after these changes. </p>
<pre class="brush: bash; title: ; notranslate">
service postfix restart
</pre>
<p>For information of what these values mean, check the links at the end of this post. If you do</p>
<pre class="brush: bash; title: ; notranslate">
sockstat -4 
</pre>
<p>you’ll see that postfix is also listening on port 587. Allow this port on the firewall if you have it enabled, but don’t close port 25. This port is used for server to server communication. If you do <strong>telnet localhost 587</strong> and type <strong>EHLO something.com</strong> you should see that postfix replies with STARTTLS.</p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2014/11/P048-06.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2014/11/P048-06.png" alt="" width="408" height="336" class="aligncenter size-full wp-image-7158" srcset="https://blog.andreev.it/wp-content/uploads/2014/11/P048-06.png 408w, https://blog.andreev.it/wp-content/uploads/2014/11/P048-06-300x247.png 300w" sizes="(max-width: 408px) 100vw, 408px" /></a></p>
<h1>dovecot and SSL</h1>
<p>Edit <strong>10-auth.conf</strong> and change:</p>
<pre class="brush: bash; title: ; notranslate">
disable_plaintext_auth = yes
</pre>
<p>Then, edit <strong>10-ssl.conf</strong> and change:</p>
<pre class="brush: bash; title: ; notranslate">
ssl = yes
ssl_cert = &lt;/usr/local/etc/postfix/server.crt
ssl_key = &lt;/usr/local/etc/postfix/myserver.key
</pre>
<p>We’ll use self-signed certificates, but check <a href="http://www.startssl.com" target="_blank" rel="noopener noreferrer">http://www.startssl.com</a> for free certificates. Unlike virtual Apache domains, you don’t need multiple certificates for each virtual domain. Self-signed certificates are fake, so you’ll get a prompt to accept a fake certificate when you try to send/receive an email, but the goal is to show you how to use them, not to be a 100% compliant.</p>
<pre class="brush: bash; title: ; notranslate">
cd /usr/local/etc/postfix
openssl genrsa -out myserver.key 1024
openssl req -new -key myserver.key -out myserver.csr
</pre>
<p>You have to answer some questions for the certificate request.</p>
<pre class="brush: plain; highlight: [8,9,10,11,13,14]; title: ; notranslate">
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) &#x5B;AU]:US
State or Province Name (full name) &#x5B;Some-State]:NJ
Locality Name (eg, city) &#x5B;]:Lawrenceville
Organization Name (eg, company) &#x5B;Internet Widgits Pty Ltd]:Joe's Plumbing
Organizational Unit Name (eg, section) &#x5B;]:
Common Name (e.g. server FQDN or YOUR name) &#x5B;]:www.domain-one.com
Email Address &#x5B;]:joe@domain-one.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password &#x5B;]:
An optional company name &#x5B;]:
</pre>
<p>Sign the certificate.</p>
<pre class="brush: bash; title: ; notranslate">
openssl x509 -req -days 3650 -in myserver.csr -signkey myserver.key -out server.crt
</pre>
<p>Copy <strong>server.crt</strong> and <strong>myserver.key</strong> under <strong>/usr/local/etc/postfix</strong> and restart both postfix and dovecot.</p>
<pre class="brush: bash; title: ; notranslate">
service postfix restart
service dovecot restart
</pre>
<p>You can test SMTP SSL/TLS on submission port 587.</p>
<pre class="brush: bash; title: ; notranslate">
openssl s_client -starttls smtp -connect localhost:587
</pre>
<p>Then type <strong>ehlo something.com</strong> , hit ENTER and then <strong>mail from:joe@domain-one.com</strong>. If these steps work, you should be OK. To test SASL with postfix and dovecot, type:</p>
<pre class="brush: bash; title: ; notranslate">
doveadm auth test -a /var/spool/postfix/private/auth joe@domain-one.com joe's_passwd
</pre>
<p>You should receive <strong>passdb: joe@domain-one.com auth succeeded.</strong></p>
<p>At this point, you should be able to send e-mails from your favorite MUA, but you’ll have to make some changes in order to send and receive. For example, in Outlook, you should use these settings.</p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2014/11/P048-07.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2014/11/P048-07.png" alt="" width="381" height="179" class="aligncenter size-full wp-image-7159" srcset="https://blog.andreev.it/wp-content/uploads/2014/11/P048-07.png 381w, https://blog.andreev.it/wp-content/uploads/2014/11/P048-07-300x141.png 300w" sizes="(max-width: 381px) 100vw, 381px" /></a></p>
<p>So, no more port 110 and 143. Instead use 995 for POP3s, 587 for SMPT (SASL) and 993 for IMAPs. The username is your e-mail address and the password is the one that you generated with <strong>doveadm pw</strong> command.</p>
<h1>Roundcube IMAP webmail client</h1>
<p>In order to send/receive e-mails using a web client, you can use Roundcube. Please follow these guides to install it. </p>
<p><a href="https://blog.andreev.it/?p=1309" target="_blank" rel="noopener noreferrer">FreeBSD 10: Apache, PHP and MySQL</a><br />
<a href="https://blog.andreev.it/?p=1339" target="_blank" rel="noopener noreferrer">FreeBSD 10: Install Roundcube Web Mail Client</a></p>
<h1>Amavisd, Spamassassin and clamav</h1>
<p>This software trio is used to fight spam messages and e-mails with virus attachments. Amavisd is used as an interface between postfix as MTA (mail transfer agent) and the content checkers (spamassassin and clamav). There are no specific configurations, so we&#8217;ll install them from the packages. </p>
<pre class="brush: bash; title: ; notranslate">
pkg install amavisd-new
pkg install clamav
</pre>
<p>Spamassassin is a dependency for amavisd so it will be installed automatically. First, let&#8217;s configure amavisd. The configuration file is <strong>/usr/local/etc/amavisd.conf</strong>. Edit this file and make sure that these values are correct. </p>
<pre class="brush: bash; title: ; notranslate">
# @bypass_virus_checks_maps = (1);  # controls running of anti-virus code
# @bypass_spam_checks_maps  = (1);  # controls running of anti-spam code
# $bypass_decode_parts = 1;         # controls running of decoders&amp;dearchivers
$daemon_user  = 'vscan';     # (no default;  customary: vscan or amavis), -u
$daemon_group = 'vscan';     # (no default;  customary: vscan or amavis), -g
$mydomain = 'example.com';   # a convenient default for other settings (change it)
$MYHOME = '/var/amavis';   # a convenient default for other settings, -H (remove the comment in front)
@local_domains_maps = ( &#x5B;&quot;.$mydomain&quot;,&quot;myotherdomain.net&quot;] );  # list of all local domains
$myhostname = 'host.example.com';  # must be a fully-qualified domain name! (remove the comment in front)
</pre>
<p>There are a lot of changes that you can configure, but these are the basic ones. See the <a href="http://www.ijs.si/software/amavisd/" target="_blank" rel="noopener noreferrer">official page</a> for more information.<br />
Finally, let&#8217;s make another change in this file, so amavisd and clamav know about each other. Remove the comments from lines 2 to 5.</p>
<div style="border:1px solid red; padding:16px;">
<p style="text-align:center;"><strong><span style="color:#800000;">NOTE ABOUT MEMORY</span> </strong></p>
<p>Clamav eats up a lot of memory. You won&#8217;t be able to run it on a server with less than 2GB RAM. If you feel comfortable, you can disable it. Don&#8217;t uncomment the lines below, remove the comment from # @bypass_virus_checks_maps = (1);  # controls running of anti-virus code and remove it from rc.conf if you already installed it. </p>
</div>
<pre class="brush: bash; highlight: [2,3,4,5]; title: ; notranslate">
# ### http://www.clamav.net/
&#x5B;'ClamAV-clamd',
  \&amp;ask_daemon, &#x5B;&quot;CONTSCAN {}\n&quot;, &quot;/var/run/clamav/clamd.sock.sock&quot;],
  qr/\bOK$/m, qr/\bFOUND$/m,
  qr/^.*?: (?!Infected Archive)(.*) FOUND$/m ],
# # NOTE: run clamd under the same user as amavisd - or run it under its own
# #   uid such as clamav, add user clamav to the amavis group, and then add
# #   AllowSupplementaryGroups to clamd.conf;
# # NOTE: match socket name (LocalSocket) in clamav.conf to the socket name in
# #   this entry; when running chrooted one may prefer a socket under $MYHOME.
</pre>
<p>The default <strong>amavisd.conf</strong> file comes with &#8220;sock.sock&#8221; in line 3. Remove it, so line 3 looks like</p>
<pre class="brush: bash; first-line: 3; title: ; notranslate">
  \&amp;ask_daemon, &#x5B;&quot;CONTSCAN {}\n&quot;, &quot;/var/run/clamav/clamd.sock&quot;],
</pre>
<p>Now, edit <strong>/etc/group</strong> and add <strong>clamav</strong> as a member of <strong>vscan</strong> group so it looks like this.</p>
<pre class="brush: bash; title: ; notranslate">
vscan:*:110:clamav 
</pre>
<p>Then check the configuration file for clamav (<strong>/usr/local/etc/clamd.conf</strong>) and make sure that this line exists.</p>
<pre class="brush: bash; title: ; notranslate">
AllowSupplementaryGroups yes 
</pre>
<p>Now, let&#8217;s tie everything together with postfix. Edit <strong>/usr/local/etc/postfix/master.cf</strong> and add these lines at the end.</p>
<pre class="brush: bash; title: ; notranslate">
# Amavisd
amavisfeed unix - - n - 2 lmtp
        -o lmtp_data_done_timeout=1200
        -o lmtp_send_xforward_command=yes
127.0.0.1:10025 inet n - n - - smtpd
        -o content_filter=
        -o smtpd_delay_reject=no
        -o smtpd_client_restrictions=permit_mynetworks,reject
        -o smtpd_helo_restrictions=
        -o smtpd_sender_restrictions=
        -o smtpd_recipient_restrictions=permit_mynetworks,reject
        -o smtpd_data_restrictions=reject_unauth_pipelining
        -o smtpd_end_of_data_restrictions=
        -o smtpd_restriction_classes=
        -o mynetworks=127.0.0.0/8
        -o smtpd_error_sleep_time=0
        -o smtpd_soft_error_limit=1001
        -o smtpd_hard_error_limit=1000
        -o smtpd_client_connection_count_limit=0
        -o smtpd_client_connection_rate_limit=0
        -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_milters,no_address_mappings
        -o local_header_rewrite_clients=
        -o smtpd_milters=
        -o local_recipient_maps=
        -o relay_recipient_maps=
</pre>
<p>Edit <strong>/usr/local/etc/postfix/main.cf</strong> and add these lines at the end.</p>
<pre class="brush: bash; title: ; notranslate">
# Amavisd
content_filter = amavisfeed:&#x5B;127.0.0.1]:10024
</pre>
<p>Let&#8217;s make sure that our trio starts on each reboot. Edit <strong>/etc/rc.conf</strong> and add these lines.</p>
<pre class="brush: bash; title: ; notranslate">
amavisd_enable=&quot;YES&quot;
clamav_clamd_enable=&quot;YES&quot;
clamav_freshclam_enable=&quot;YES&quot;
spamd_enable=&quot;YES&quot; 
</pre>
<p>The <strong>clamav_freshclam</strong> daemon part is to update the anti-virus signatures. For updating spamassassin&#8217;s definitions and signatures, we&#8217;ll have to run a cron job. First, let&#8217;s do an initial run for spamassassin.</p>
<pre class="brush: bash; title: ; notranslate">
sa-update -D
</pre>
<p>The &#8220;-D&#8221; option is to run in debug mode so you can see what&#8217;s going on. If there is an update available, spamassassin&#8217;s exit code is 0, if not the exit code is 1. In case there is an update, we&#8217;ll have to restart the spamassassin&#8217;s daemon. So, let&#8217;s create a cron job that runs once a day and checks for updates. </p>
<pre class="brush: bash; title: ; notranslate">
crontab -e
</pre>
<p>Add this line so the updates start 1 minute after midnight.</p>
<pre class="brush: bash; title: ; notranslate">
1 0 * * * /usr/local/bin/sa-update &amp;&amp; /usr/local/sbin/service sa-spamd restart
</pre>
<p>Once we took care of the updates part, let&#8217;s start spamassassin.</p>
<pre class="brush: bash; title: ; notranslate">
service sa-spamd start
</pre>
<p>Let&#8217;s do an initial run for clamav.</p>
<pre class="brush: bash; title: ; notranslate">
freshclam
</pre>
<p>You&#8217;ll see a warning, but ignore that. clamav daemon is still not started.</p>
<pre class="brush: bash; gutter: false; title: ; notranslate">
ClamAV update process started at Sun Nov 2 18:49:06 2014
main.cvd is up to date (version: 55, sigs: 2424225, f-level: 60, builder: neo)
daily.cvd is up to date (version: 19576, sigs: 1244373, f-level: 63, builder: neo)
bytecode.cvd is up to date (version: 242, sigs: 46, f-level: 63, builder: dgoddard)
WARNING: Clamd was NOT notified: Can't connect to clamd through /var/run/clamav/clamd.sock: No such file or directory 
</pre>
<p>Finally, let&#8217;s start the services and restart postfix.</p>
<pre class="brush: bash; title: ; notranslate">
service clamav-clamd start
service clamav-freshclam start
service amavisd start 
service postfix restart
</pre>
<p>Check the connection between amavisd and postfix.</p>
<pre class="brush: bash; title: ; notranslate">
telnet localhost 10024
</pre>
<p>Type <strong>ehlo localhost</strong> and check the ouput. In my case it looks like this.</p>
<pre class="brush: bash; gutter: false; title: ; notranslate">
250-&#x5B;127.0.0.1]
250-VRFY
250-PIPELINING
250-SIZE
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250 XFORWARD NAME ADDR PORT PROTO HELO IDENT SOURCE
</pre>
<p>Then do.</p>
<pre class="brush: bash; title: ; notranslate">
telnet localhost 10025
</pre>
<p>Again, type <strong>ehlo localhost</strong> and check the ouput. In my case it looks like this.</p>
<pre class="brush: bash; gutter: false; title: ; notranslate">
250-www.testcloudserver.org
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
</pre>
<p>And finally, some real tests. First, check the mail log file.</p>
<pre class="brush: bash; title: ; notranslate">
tail -f /var/log/maillog
</pre>
<p>Then, from another e-mail account, send a text (not HTML) e-mail with this in the body.</p>
<pre class="brush: bash; gutter: false; title: ; notranslate">
X5O!P%@AP&#x5B;4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*
</pre>
<p>You should see something like this in the logs.</p>
<pre class="brush: plain; gutter: false; title: ; notranslate">
Nov  7 17:33:02 www amavis&#x5B;966]: (00966-01) Blocked INFECTED (Eicar-Test-Signature) {DiscardedInbound,Quarantined}, &#x5B;104.207.128.32]:28661 &#x5B;104.207.128.32] &lt;klimenta@iandreev.com&gt; -&gt; &lt;klimenta@testcloudserver.us&gt;, quarantine: virus-G9s83IyyvqaS, Queue-ID: 130DDFA76, Message-ID: &lt;fbaa61e9ca8c994b4f0278f258652140@iandreev.com&gt;, mail_id: G9s83IyyvqaS, Hits: -, size: 952, 172 ms
Nov  7 17:33:02 www postfix/lmtp&#x5B;1167]: 130DDFA76: to=&lt;klimenta@testcloudserver.us&gt;, relay=127.0.0.1&#x5B;127.0.0.1]:10024, delay=0.21, delays=0.03/0.01/0.01/0.17, dsn=2.7.0, status=sent (250 2.7.0 Ok, discarded, id=00966-01 - INFECTED: Eicar-Test-Signature)
Nov  7 17:33:02 www postfix/qmgr&#x5B;1063]: 130DDFA76: removed
Nov  7 17:33:02 www postfix/qmgr&#x5B;1063]: 43707FA84: from=&lt;virusalert@testcloudserver.us&gt;, size=2765, nrcpt=1 (queue active)
Nov  7 17:33:02 www postfix/virtual&#x5B;1170]: 43707FA84: to=&lt;virusalert@testcloudserver.us&gt;, relay=virtual, delay=0.02, delays=0.01/0.01/0/0, dsn=2.0.0, status=sent (delivered to maildir)
Nov  7 17:33:02 www postfix/qmgr&#x5B;1063]: 43707FA84: removed
</pre>
<p>The e-mail won&#8217;t be delivered to the recipient, instead the message will be forwarded to the <strong>virusalert</strong> account. I don&#8217;t have this account created as virtual account, but I have a <strong>catch-all</strong> virtual account, so this is what I&#8217;ve received in Roundcube.</p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2014/11/P048-08.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2014/11/P048-08.png" alt="" width="580" height="650" class="aligncenter size-full wp-image-7160" srcset="https://blog.andreev.it/wp-content/uploads/2014/11/P048-08.png 580w, https://blog.andreev.it/wp-content/uploads/2014/11/P048-08-268x300.png 268w" sizes="(max-width: 580px) 100vw, 580px" /></a><br />
Leave the log file open and let&#8217;s send another test e-mail, same text format, but this time put this line in the body of the message.</p>
<pre class="brush: bash; gutter: false; title: ; notranslate">
XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X
</pre>
<p>You should see something like this in the log file.</p>
<pre class="brush: bash; gutter: false; title: ; notranslate">
Nov  7 17:41:44 www amavis&#x5B;965]: (00965-01) Passed SPAM {RelayedTaggedInbound,Quarantined}, &#x5B;104.207.128.32]:57855 &#x5B;104.207.128.32] &lt;klimenta@iandreev.com&gt; -&gt; &lt;klimenta@testcloudserver.us&gt;, quarantine: spam-hPo7Kn_vhzBm.gz, Queue-ID: 3A733FA72, Message-ID: &lt;fce64236c0e9432da776553dba2f6ba2@iandreev.com&gt;, mail_id: hPo7Kn_vhzBm, Hits: 999.407, size: 947, queued_as: 98A9AFA76, 364 ms
</pre>
<p>If you check your e-mail, you&#8217;ll see this in your inbox.</p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2014/11/P048-09.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2014/11/P048-09.png" alt="" width="526" height="143" class="aligncenter size-full wp-image-7161" srcset="https://blog.andreev.it/wp-content/uploads/2014/11/P048-09.png 526w, https://blog.andreev.it/wp-content/uploads/2014/11/P048-09-300x82.png 300w" sizes="(max-width: 526px) 100vw, 526px" /></a><br />
Now that we have spam and anti-virus covered, we&#8217;ll discuss another topic. And that&#8217;s e-mail filtering and sorting.</p>
<h1>dovecot pigeonhole</h1>
<p>There are many other options that can be used for e-mail filtering and sorting, but <a href="http://pigeonhole.dovecot.org/" target="_blank" rel="noopener noreferrer">pigeonhole</a> uses <a href="http://sieve.info/" target="_blank" rel="noopener noreferrer">Sieve language</a> and it&#8217;s very powerful.<br />
Let&#8217;s install it from the packages. </p>
<pre class="brush: bash; title: ; notranslate">
pkg install dovecot-pigeonhole
cd /usr/local/etc/dovecot/conf.d
cp /usr/local/share/doc/dovecot-pigeonhole/example-config/conf.d/* .
</pre>
<p>This will copy three files to the existing configuration files (<strong>20-managesieve.conf, 90-sieve-extprograms.conf</strong> and <strong>90-sieve.conf</strong>). Let&#8217;s make the following changes.<br />
In <strong>/usr/local/etc/postfix/main.cf</strong> add these lines at the end.</p>
<pre class="brush: bash; title: ; notranslate">
# LMTP
virtual_transport = lmtp:unix:private/dovecot-lmtp
</pre>
<div style="border:1px solid red; padding:16px;">
<p style="text-align:center;"><strong><span style="color:#800000;">NOTE ABOUT VIRTUAL USERS</span> </strong></p>
<p>Once you enable virtual_transport in main.cf, postfix virutal users won&#8217;t have any effect. All virtual users are defined in /usr/local/etc/dovecot/users file from now on and dovecot will take care of mail delivery.</p>
</div>
<p>Then edit the following files under <strong>/usr/local/etc/dovecot/conf.d/</strong> and make sure that these parameters are as below.<br />
<strong>10-mail.conf</strong></p>
<pre class="brush: bash; title: ; notranslate">
mail_home = /var/mail/vhosts/%d/%n
mail_location = maildir:~
mail_privileged_group = vpostfix
</pre>
<p><strong>10-master.conf</strong></p>
<pre class="brush: bash; title: ; notranslate">
service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    mode = 0600
    user = postfix
    group = postfix
  }
</pre>
<p><strong>15-lda.conf</strong></p>
<pre class="brush: bash; title: ; notranslate">
recipient_delimiter = +
mail_plugins = $mail_plugins sieve
</pre>
<p><strong>20-lmtp.conf</strong></p>
<pre class="brush: bash; title: ; notranslate">
lmtp_save_to_detail_mailbox = yes
protocol lmtp {
  # Space separated list of plugins to load (default is global mail_plugins).
  postmaster_address = joe@whatsup.com
  mail_plugins = $mail_plugins sieve
}
</pre>
<p><strong>90-sieve.com</strong></p>
<pre class="brush: bash; title: ; notranslate">
recipient_delimiter = +
</pre>
<p>Now, go to the mail directory of one of the virtual users.</p>
<pre class="brush: bash; title: ; notranslate">
cd /var/mail/vhosts/domain-one.com/joe
</pre>
<p>and create this file <strong>.dovecot.sieve</strong> with the following Sieve commands inside.</p>
<pre class="brush: bash; title: ; notranslate">
require &quot;fileinto&quot;;
if header :comparator &quot;i;ascii-casemap&quot; :contains &quot;Subject&quot; &quot;***Spam***&quot;  {
        fileinto &quot;Junk&quot;;
        stop;
}
</pre>
<p>This means that if an e-mail arrives flagged with &#8220;<strong>***Spam***</strong>&#8221; in the subject (as we configured Spamassassin), then move it to the &#8220;<strong>Junk</strong>&#8221; folder (make sure that you have Junk IMAP folder created).<br />
Restart both postfix and dovecot and you are all set.</p>
<pre class="brush: bash; title: ; notranslate">
service postfix restart
service dovecot restart
</pre>
<h1>Stress test</h1>
<p>From another server with postfix installed, do:</p>
<pre class="brush: bash; title: ; notranslate">
time /usr/sbin/smtp-source -s 40 -l 10120 -m 5000 -c -f user@whatsup.com -t joe@domain-one.com mail.domain-one.com:25
</pre>
<p>On your server do:</p>
<pre class="brush: bash; title: ; notranslate">
tail -f /var/log/maillog
</pre>
<p><strong>smtp-source</strong> comes up with FreeBSD only if you select <strong>TEST</strong> during the install, but it comes with CentOS in the default install.<br />
Make sure that the server where you run <strong>smtp-source</strong> is a legit server, otherwise your postfix will just reject all messages.<br />
Watch how your log file gets bombarded with messages. You can also watch the queue real-time with:</p>
<pre class="brush: bash; title: ; notranslate">
postqueue -p
</pre>
<p>If you are satisfied with the results after 5-10 mins, empty the postfix queue with:</p>
<pre class="brush: bash; title: ; notranslate">
postsuper -d ALL
</pre>
<h1>Issues with clamav</h1>
<p>I was testing the whole scenario on a 768MB RAM server. For some reason, clamav eats up a lot of memory.<br />
You might see this in <strong>/var/log/messages</strong> when you try to start the daemon.</p>
<pre class="brush: bash; gutter: false; title: ; notranslate">
Nov  7 22:04:03 www kernel: pid 997 (clamd), uid 106, was killed: out of swap space
</pre>
<p>My <a href="http://www.vultr.com" target="_blank" rel="noopener noreferrer">VPS</a> had no swap space when purchased. From what I see, clamav is memory hungry and while there are some workarounds, the easiest way is to create a swap partition. FreeBSD 10 has a wonderful option to create a swap without a dedicated partition. You just create a file that will be used as a swap. So, if you have a server with less than 4GB RAM and no swap partition, do the <a href="https://www.freebsd.org/doc/handbook/adding-swap-space.html" target="_blank" rel="noopener noreferrer">following</a>.</p>
<pre class="brush: bash; title: ; notranslate">
dd if=/dev/zero of=/usr/swap0 bs=1m count=1024
</pre>
<p>where <strong>1024</strong> means 1GB file. Then, change the permissions. </p>
<pre class="brush: bash; title: ; notranslate">
chmod 0600 /usr/swap0
</pre>
<p>Edit <strong>/etc/fstab</strong> and add this line.</p>
<pre class="brush: bash; title: ; notranslate">
md99	none	swap	sw,file=/usr/swap0	0	0
</pre>
<p>Reboot after this. You can do <strong>&#8220;swapon -aq&#8221;</strong> without a reboot, but it didn&#8217;t work for me.<br />
Anyway, type:</p>
<pre class="brush: bash; title: ; notranslate">
swapinfo
</pre>
<p>to see the swap usage.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2014/11/freebsd-10-postfix-dovecot-amavisd-new-spamassassin-clamav-pigeonhole/feed/</wfw:commentRss>
			<slash:comments>29</slash:comments>
		
		
			</item>
	</channel>
</rss>
