Set Up Dovecot
(1) Install the packages
apt-get install dovecot-imapd
The Dovecot config file is located at /etc/dovecot/dovecot.conf. Edit it and make following changes:
(2) Add Maildir
Search for
#mail_location =
and add below
mail_location = maildir:~/Maildir
(3) Add authentication
Search for
auth default {
rename it to
auth default2 {
and add above
auth default {
mechanisms = plain login
passdb pam {
}
userdb passwd {
}
socket listen {
client {
path = /var/spool/postfix/private/auth
mode = 0660
user = postfix
group = postfix
}
}
}
(3) Restart Dovecot
/etc/init.d/dovecot restart
By default only IMAP and IMAPs is enabled on dovecot. I don't see any point nowadays in POP3 hence the according daemon is not being installed and activated.
Set Up Email Address Management
Now we actually have a fully functioning mail server. The only problem is, the mailserver does not yet know what to do with incoming email.
When we added this "virtual_maps = hash:/etc/postfix/virtual" to the postfix config we told the server, that the incoming email address and their destination is to be found in this file. This file has a very simple structure:
USER@MYDOMAIN.COM SYSUSER
In that case incoming email to the "USER@MYDOMAIN.COM" email address will be put into the Maildir of the system user "SYSUSER".
Assuming my username on the system is "testuser" and I setup a recipient address for my buddy John Doe like "from.john.doe@testuser.com" then I would have an entry like this:
from.john.doe@testuser.com testuser
If only that would be in the virtual table and an email with recipient address "really.from.john.doe@testuser.com" would arrive, then Postfix can't find a match and it will reject it. The sender will get an according notice, that this email address does not exist.
This means we can easily just add hundreds and thousands of email addresses there and tell they should all go to the "testuser" account. When I then notice, I get spam to specific incoming email address, I can simply remove that one.
HOWEVER, just creating that file doesn't do the job. There are two more steps required after each edit:
postmap /etc/postfix/virtual
/etc/init.d/postfix reload
The first one converts the virtual file into a hashed virtual.db file which makes it faster for postfix to process and the second command reloads the file.
Always editing this by hand is cumbersome. Hence I created myself a little PHP script which makes it simple. It only has two options:
- adding new incoming email addresses
- remove existing entries
In order to prevent any abuse, a few precautions have to be taken. Namely:
- According access to the script is only possible with HTTPS
- Username and password are required to login
- virtual file is not directly altered but updated with cron
(1) Install packages
apt-get install libapache2-mod-php5
This will install Apache, PHP5, PHP5 Module and PHP5 Cli.
(2) Create SSL certificate for Apache
openssl req $@ -new -x509 -days 3650 -nodes -out /etc/apache2/apache.pem -keyout /etc/apache2/apache.pem
(3) Create the email webfolder
mkdir -p /var/www/email
(4) Edit /var/www/email/.htaccess and add
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
(5) Edit /var/www/email/index.php and add
<?php
$sysuser = 'USERNAME';
$domain = 'MYDOMAIN.COM';
#######################################################################################################
# #
# #
# DO NOT EDIT BELOW #
# #
# #
#######################################################################################################
$email = $_POST['email'];
$pg = $_POST['submit'];
if($pg == '') { $pg = $_GET['pg']; }
switch ($pg) {
case 'Add':
$output = add_email($email, $domain, $sysuser);
break;
case 'Remove':
$output = remove_email($email);
break;
case 'RemoveForm':
$output = remove_form();
break;
default:
$output = add_form();
}
$output = f_header() . $output . f_footer();
echo $output;
function f_header() {
$output = "<html>\n<head>\n<title>Email Management</title>\n</head>\n
<body>\n
<a href='?pg=AddForm'>Add Email</a> | <a href='?pg=RemoveForm'>Remove Email</a><br><br>
<form name='input' action='" . $PHP_SELF . "' method='POST'>\n
";
return($output);
}
function f_footer() {
$output = "</form>\n</body>\n</html>";
return($output);
}
function add_form($added) {
$output = "$added<br>
<br>Domain '@$domain' will be automatically added.<br>
<input type='text' name='email' value='' size='30'>\n
<input type='submit' name='submit' value='Add'>\n
";
return($output);
}
function remove_form($added) {
$output = "$added<br>
<br>Only enter the 'left' part of the '@'<br>
<input type='text' name='email' value='' size='30'>\n
<input type='submit' name='submit' value='Remove'>\n
";
return($output);
}
function add_email($email, $domain, $sysuser) {
$myFile = "add.txt";
$write_block = $email . '@' . $domain ."\t\t\t" .$sysuser . "\n";
$fh = fopen($myFile, 'a') or die("can't open file");
fwrite($fh, $write_block);
fclose($fh);
$added = $email . "@" . $domain . " - marked for addition";
$output = add_form($added);
return($output);
}
function remove_email($email) {
$myFile = "remove.txt";
$write_block = $email . "\n";
$fh = fopen($myFile, 'a') or die("can't open file");
fwrite($fh, $write_block);
fclose($fh);
$added = $email . " - marked for removal";
$output = remove_form($added);
return($output);
}
?>
Replace at the beginning the USERNAME with your system user name and MYDOMAIN.COM with your actual domain name.
(6) Chown /var/www/email
chown -R www-data:www-data /var/www/email
(7) Enable apache modules
a2enmod ssl auth_digest rewrite
(8) Extend apach2 config
echo "servername localhost" >> /etc/apache2/apache2.conf
(9) Edit /etc/apache2/sites-enabled/000-default
Insert after
<Directory /var/www/>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all
</Directory>
this
<Directory /var/www/email/>
AllowOverride All
Order allow,deny
allow from all
</Directory>
(10) Still editing the /etc/apache2/sites-enabled/000-default add at the end of the file the following
<VirtualHost *:443>
ServerAdmin webmaster@localhost
SSLEngine on
SSLCertificateFile /etc/apache2/apache.pem
DocumentRoot /var/www/
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
<Directory /var/www/>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all
</Directory>
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
<Directory "/usr/lib/cgi-bin">
AllowOverride None
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
Order allow,deny
Allow from all
</Directory>
ErrorLog /var/log/apache2/error.log
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel warn
CustomLog /var/log/apache2/access.log combined
Alias /doc/ "/usr/share/doc/"
<Directory "/usr/share/doc/">
Options Indexes MultiViews FollowSymLinks
AllowOverride None
Order deny,allow
Deny from all
Allow from 127.0.0.0/255.0.0.0 ::1/128
</Directory>
<Location /email>
AuthType Digest
AuthName "email"
AuthDigestDomain /var/www/email/ http://MYDOMAIN.COM/email
AuthDigestProvider file
AuthUserFile /etc/apache2/passwords
Require valid-user
SetEnv R_ENV "/var/www/email"
</Location>
</VirtualHost>
(11) Add yourself to authdigest
htdigest -c /etc/apache2/passwords email USERLOGIN
Enter a desired username for USERLOGIN and enter twice the desired password.
(12) Restart Apache
/etc/init.d/apache2 restart
What we have now is an auto-redirect to SSL version of the email management script. When successfully logged in, the script will create an "add.txt" and "remove.txt" file when email addresses should be added/removed.
The missing piece now is to communicate those changes with postfix. For this, we just add another small shell script and add that one to cron.
(13) Edit /root/email_virtual.sh and add:
#!/bin/bash
ADD="/var/www/email/add.txt"
REMOVE="/var/www/email/remove.txt"
DEST="/etc/postfix/virtual"
if [ -f $ADD ]
then
while read CURLINE; do
# echo $CURLINE
echo $CURLINE >> $DEST
done < $ADD
rm $ADD
fi
if [ -f $REMOVE ]
then
while read CURLINE; do
# echo $CURLINE
sed -i "/$CURLINE/ d" $DEST
done < $REMOVE
rm $REMOVE
fi
postmap /etc/postfix/virtual
/etc/init.d/postfix reload
(14) Make it executable
cd /root
chmod 0700 email_virtual.sh
(15) Add the script to the cron.txt
echo "*/2 * * * * virtual_email.sh >/dev/null 2>&1" >> cron.txt
(16) Load the new cron.txt
crontab cron.txt
(17) Display current crons
crontab -l