Tutoriel N° 2e8
Postfix configuration ubuntu 18.04 / Virtualmin / Manage incoming outgoing email and bounces
First:
1/ You need install your Ubuntu server with virtualmin before to follow this tutoriel
2/ bind9 need to be launch, you an check it with this command:
service --status-all
3/ Manage your DNS zone with a local MX
https://www.shareannonce.com/david/tutorial/2e7
Then:
Webmin configuration:
Create mailbox: team@shareannonce.com
Create mailbox: contact@shareannonce.com
Create mailbox: bounce@shareannonce.com
Gmail receive email forwarding: mailredirect@gmail.com
team@shareannonce.com mailbox needn't more configuration to receive email in your webmail SquirrelMail (per exemple)
Files you need to modify:
/etc/aliases
/etc/postfix/main.cf
/etc/postfix/master.cf
/etc/postfix/virtual
File you need to create:
/home/shareannonce/public_html/bounceforward.php
nano /etc/aliases
# See man 5 aliases for format
# forward contact@shareannonce.com on mailredirect@gmail.com
contact-shareannonce.com: mailredirect@gmail.com
# 1/ receive bounce on your mailbox first bounce@shareannonce.com
# 2/ catch bounce error with this script bounceforward.php
# 3/ you need respect this order receive bounce then forward this on script
# (*)
bounce-shareannonce.com: bounce-shareannonce.com "|/home/shareannonce/public_html/bounceforward.php"
# forward contact@shareannonce.com on mailredirect@gmail.com
contact-shareannonce.com: mailredirect@gmail.com
# 1/ receive bounce on your mailbox first bounce@shareannonce.com
# 2/ catch bounce error with this script bounceforward.php
# 3/ you need respect this order receive bounce then forward this on script
# (*)
bounce-shareannonce.com: bounce-shareannonce.com "|/home/shareannonce/public_html/bounceforward.php"
nano /etc/postfix/main.cf
Modify or add thoses lines at the end
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
myhostname = shareannonce.com
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = /etc/mailname
mydestination = $myhostname, localhost.$mydomain, $mydomain
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
#mailbox_size_limit = 1000000000
recipient_delimiter = +
inet_protocols = all
#inet_protocols = ipv4
virtual_alias_maps = hash:/etc/postfix/virtual
virtual_alias_domains = shareannonce.com anotherdomain.com
# add here all user can use forward bounces separate by a space
# only one user, and bounceforward.php will be always in chmod 755 in shareann folder
default_privs = shareann
sender_bcc_maps = hash:/etc/postfix/bcc
mailbox_command = /usr/bin/procmail-wrapper -o -a $DOMAIN -d $LOGNAME
home_mailbox = Maildir/
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
broken_sasl_auth_clients = yes
smtpd_recipient_restrictions = permit_mynetworks permit_sasl_authenticated reject_unauth_destination
smtp_tls_security_level = may
smtp_tls_loglevel = 1
allow_percent_hack = no
milter_default_action = accept
milter_protocol = 2
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891
mynetworks_style = subnet
myhostname = shareannonce.com
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = /etc/mailname
mydestination = $myhostname, localhost.$mydomain, $mydomain
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
#mailbox_size_limit = 1000000000
recipient_delimiter = +
inet_protocols = all
#inet_protocols = ipv4
virtual_alias_maps = hash:/etc/postfix/virtual
virtual_alias_domains = shareannonce.com anotherdomain.com
# add here all user can use forward bounces separate by a space
# only one user, and bounceforward.php will be always in chmod 755 in shareann folder
default_privs = shareann
sender_bcc_maps = hash:/etc/postfix/bcc
mailbox_command = /usr/bin/procmail-wrapper -o -a $DOMAIN -d $LOGNAME
home_mailbox = Maildir/
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
broken_sasl_auth_clients = yes
smtpd_recipient_restrictions = permit_mynetworks permit_sasl_authenticated reject_unauth_destination
smtp_tls_security_level = may
smtp_tls_loglevel = 1
allow_percent_hack = no
milter_default_action = accept
milter_protocol = 2
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891
mynetworks_style = subnet
nano /etc/postfix/master.cf
#
# Postfix master process configuration file. For details on the format
# of the file, see the master(5) manual page (command: "man 5 master").
#
# Do not forget to execute "postfix reload" after editing this file.
#
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (yes) (never) (100)
# ==========================================================================
smtp inet n - n - - smtpd
587 inet n - n - - smtpd
-o smtpd_tls_security_level=encrypt
-o smtpd_tls_auth_only=yes
-o smtpd_tls_cert_file=/etc/pki/tls/certs/localhost.crt
-o smtpd_tls_key_file=/etc/pki/tls/private/localhost.key
-o smtpd_sasl_type=dovecot
-o smtpd_sasl_auth_enable=yes
-o smtpd_sasl_path=/var/spool/postfix/private/auth
-o smtpd_recipient_restrictions=$external_submission_restrictions
-o receive_override_options=no_address_mappings
pickup fifo n - n 60 1 pickup
cleanup unix n - n - 0 cleanup
qmgr fifo n - n 300 1 qmgr
tlsmgr unix - - n 1000? 1 tlsmgr
rewrite unix - - n - - trivial-rewrite
-o append_at_myorigin=no
bounce unix - - n - 0 bounce
defer unix - - n - 0 bounce
trace unix - - n - 0 bounce
verify unix - - n - 1 verify
flush unix n - n 1000? 0 flush
proxymap unix - - n - - proxymap
proxywrite unix - - n - 1 proxymap
smtp unix - - n - - smtp
relay unix - - n - - smtp
-o smtp_fallback_relay=
showq unix n - n - - showq
error unix - - n - - error
retry unix - - n - - error
discard unix - - n - - discard
local unix - n n - - local
virtual unix - n n - - virtual
lmtp unix - - n - - lmtp
anvil unix - - n - 1 anvil
scache unix - - n - 1 scache
dovecot unix - n n - - pipe
flags=DRhu user=mailboxes:mailboxes argv=/usr/libexec/dovecot/deliver -f ${sender} -d ${user}@${nexthop}
amavisfeed unix - - n - 2 smtp
-o smtp_data_done_timeout=1200
-o smtp_send_xforward_command=yes
-o disable_dns_lookup=yes
-o max_use=20
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 receive_override_options=no_address_mappings
-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=
vacation unix - n n - - pipe
flags=Rq user=vacation argv=/var/spool/vacation/vacation.pl -f ${sender} -- ${recipient}
# Postfix master process configuration file. For details on the format
# of the file, see the master(5) manual page (command: "man 5 master").
#
# Do not forget to execute "postfix reload" after editing this file.
#
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (yes) (never) (100)
# ==========================================================================
smtp inet n - n - - smtpd
587 inet n - n - - smtpd
-o smtpd_tls_security_level=encrypt
-o smtpd_tls_auth_only=yes
-o smtpd_tls_cert_file=/etc/pki/tls/certs/localhost.crt
-o smtpd_tls_key_file=/etc/pki/tls/private/localhost.key
-o smtpd_sasl_type=dovecot
-o smtpd_sasl_auth_enable=yes
-o smtpd_sasl_path=/var/spool/postfix/private/auth
-o smtpd_recipient_restrictions=$external_submission_restrictions
-o receive_override_options=no_address_mappings
pickup fifo n - n 60 1 pickup
cleanup unix n - n - 0 cleanup
qmgr fifo n - n 300 1 qmgr
tlsmgr unix - - n 1000? 1 tlsmgr
rewrite unix - - n - - trivial-rewrite
-o append_at_myorigin=no
bounce unix - - n - 0 bounce
defer unix - - n - 0 bounce
trace unix - - n - 0 bounce
verify unix - - n - 1 verify
flush unix n - n 1000? 0 flush
proxymap unix - - n - - proxymap
proxywrite unix - - n - 1 proxymap
smtp unix - - n - - smtp
relay unix - - n - - smtp
-o smtp_fallback_relay=
showq unix n - n - - showq
error unix - - n - - error
retry unix - - n - - error
discard unix - - n - - discard
local unix - n n - - local
virtual unix - n n - - virtual
lmtp unix - - n - - lmtp
anvil unix - - n - 1 anvil
scache unix - - n - 1 scache
dovecot unix - n n - - pipe
flags=DRhu user=mailboxes:mailboxes argv=/usr/libexec/dovecot/deliver -f ${sender} -d ${user}@${nexthop}
amavisfeed unix - - n - 2 smtp
-o smtp_data_done_timeout=1200
-o smtp_send_xforward_command=yes
-o disable_dns_lookup=yes
-o max_use=20
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 receive_override_options=no_address_mappings
-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=
vacation unix - n n - - pipe
flags=Rq user=vacation argv=/var/spool/vacation/vacation.pl -f ${sender} -- ${recipient}
Check virtual file:
nano /etc/postfix/virtual
team@shareannonce.com team-shareannonce.com
contact@shareannonce.com contact-shareannonce.com
bounce@shareannonce.com bounce-shareannonce.com
contact@shareannonce.com contact-shareannonce.com
bounce@shareannonce.com bounce-shareannonce.com
To update your postfix configuration:
newaliases
postmap /etc/postfix/virtual
/etc/init.d/postfix restart
postmap /etc/postfix/virtual
/etc/init.d/postfix restart
To catch your bounce email
nano /home/shareannonce/public_html/bounceforward.php
#!/usr/bin/php5.6
<?
$base='DATABASE_NAME';
$login='LOGIN';
$pwd='PASSWORD';
$host='localhost';
$db=mysql_connect($host, $login, $pwd);
if(!mysql_select_db($base,$db))
{
echo "erreur ".mysql_error()."<br>";
mysql_close($db);
exit;
}
$email = file_get_contents("php://stdin");
//*** handle email ***
$lines = explode("n", $email);
// empty vars
$from = "";
$to = "";
$date = "";
$subject = "";
$Final = "";
$message = "";
$splittingheaders = true;
for ($i=0; $i<count($lines); $i++) {
if ($splittingheaders) {
// look out for special headers
if ( (preg_match("/^Subject: (.*)/", $lines[$i], $matches)) and ($subject=="") ){
$subject = $matches[1];
}
if ( (preg_match("/^Final-Recipient: (.*)/", $lines[$i], $matches)) and ($Final=="") ){
$Final = $matches[1];
}
$bounce=explode(" ",$Final);
if ( (preg_match("/^From: (.*)/", $lines[$i], $matches)) and ($from=="") ){
if(strpos($lines[$i],"<"))
{
//the name exist too in from header
$data = explode('<',$lines[$i]);
$from = substr(trim($data[1]),0,-1);
}
else{
//only the mail
$from = $matches[1];
}
}
if (preg_match("/^To: (.*)/", $lines[$i], $matches)) {
$to = $matches[1];
}
if (preg_match("/^Date: (.*)/", $lines[$i], $matches)) {
$date = $matches[1];
}
} else {
// not a header, but message
$message .= $lines[$i]."n";
}
#if (trim($lines[$i])=="") {
if ($i==45) {
// empty line, header section has ended
$splittingheaders = false;
}
}
function extractEmailsFromString($sChaine) {
if(false !== preg_match_all('`w(?:[-_.]?w)*@w(?:[-_.]?w)*.(?:[a-z]{2,4})`', $sChaine, $aEmails)) {
if(is_array($aEmails[0]) && sizeof($aEmails[0])>0) {
return array_unique($aEmails[0]);
}
}
return null;
}
$allmail = extractEmailsFromString($email);
foreach ($allmail as $match) {
#You need create this mysql table to catch your email
#$sql="INSERT INTO bounce ( id_stats , ip , referer) VALUES (NULL, '$match', '$from');";
#mysql_query($sql);
}
//*** handle email ***
$lines = explode("n", $email);
// empty vars
$from = "";
$to = "";
$date = "";
$subject = "";
$Final = "";
$message = "";
$splittingheaders = true;
for ($i=0; $i<count($lines); $i++) {
if ($splittingheaders) {
// look out for special headers
if ( (preg_match("/^Subject: (.*)/", $lines[$i], $matches)) and ($subject=="") ){
$subject = $matches[1];
}
if ( (preg_match("/^Final-Recipient: (.*)/", $lines[$i], $matches)) and ($Final=="") ){
$Final = $matches[1];
}
$bounce=explode(" ",$Final);
if ( (preg_match("/^From: (.*)/", $lines[$i], $matches)) and ($from=="") ){
if(strpos($lines[$i],"<"))
{
//the name exist too in from header
$data = explode('<',$lines[$i]);
$from = substr(trim($data[1]),0,-1);
}
else{
//only the mail
$from = $matches[1];
}
}
if (preg_match("/^To: (.*)/", $lines[$i], $matches)) {
$to = $matches[1];
}
if (preg_match("/^Date: (.*)/", $lines[$i], $matches)) {
$date = $matches[1];
}
} else {
// not a header, but message
$message .= $lines[$i]."n";
}
#if (trim($lines[$i])=="") {
if ($i==45) {
// empty line, header section has ended
$splittingheaders = false;
}
}
mysql_close();
?>
<?
$base='DATABASE_NAME';
$login='LOGIN';
$pwd='PASSWORD';
$host='localhost';
$db=mysql_connect($host, $login, $pwd);
if(!mysql_select_db($base,$db))
{
echo "erreur ".mysql_error()."<br>";
mysql_close($db);
exit;
}
$email = file_get_contents("php://stdin");
//*** handle email ***
$lines = explode("n", $email);
// empty vars
$from = "";
$to = "";
$date = "";
$subject = "";
$Final = "";
$message = "";
$splittingheaders = true;
for ($i=0; $i<count($lines); $i++) {
if ($splittingheaders) {
// look out for special headers
if ( (preg_match("/^Subject: (.*)/", $lines[$i], $matches)) and ($subject=="") ){
$subject = $matches[1];
}
if ( (preg_match("/^Final-Recipient: (.*)/", $lines[$i], $matches)) and ($Final=="") ){
$Final = $matches[1];
}
$bounce=explode(" ",$Final);
if ( (preg_match("/^From: (.*)/", $lines[$i], $matches)) and ($from=="") ){
if(strpos($lines[$i],"<"))
{
//the name exist too in from header
$data = explode('<',$lines[$i]);
$from = substr(trim($data[1]),0,-1);
}
else{
//only the mail
$from = $matches[1];
}
}
if (preg_match("/^To: (.*)/", $lines[$i], $matches)) {
$to = $matches[1];
}
if (preg_match("/^Date: (.*)/", $lines[$i], $matches)) {
$date = $matches[1];
}
} else {
// not a header, but message
$message .= $lines[$i]."n";
}
#if (trim($lines[$i])=="") {
if ($i==45) {
// empty line, header section has ended
$splittingheaders = false;
}
}
function extractEmailsFromString($sChaine) {
if(false !== preg_match_all('`w(?:[-_.]?w)*@w(?:[-_.]?w)*.(?:[a-z]{2,4})`', $sChaine, $aEmails)) {
if(is_array($aEmails[0]) && sizeof($aEmails[0])>0) {
return array_unique($aEmails[0]);
}
}
return null;
}
$allmail = extractEmailsFromString($email);
foreach ($allmail as $match) {
#You need create this mysql table to catch your email
#$sql="INSERT INTO bounce ( id_stats , ip , referer) VALUES (NULL, '$match', '$from');";
#mysql_query($sql);
}
//*** handle email ***
$lines = explode("n", $email);
// empty vars
$from = "";
$to = "";
$date = "";
$subject = "";
$Final = "";
$message = "";
$splittingheaders = true;
for ($i=0; $i<count($lines); $i++) {
if ($splittingheaders) {
// look out for special headers
if ( (preg_match("/^Subject: (.*)/", $lines[$i], $matches)) and ($subject=="") ){
$subject = $matches[1];
}
if ( (preg_match("/^Final-Recipient: (.*)/", $lines[$i], $matches)) and ($Final=="") ){
$Final = $matches[1];
}
$bounce=explode(" ",$Final);
if ( (preg_match("/^From: (.*)/", $lines[$i], $matches)) and ($from=="") ){
if(strpos($lines[$i],"<"))
{
//the name exist too in from header
$data = explode('<',$lines[$i]);
$from = substr(trim($data[1]),0,-1);
}
else{
//only the mail
$from = $matches[1];
}
}
if (preg_match("/^To: (.*)/", $lines[$i], $matches)) {
$to = $matches[1];
}
if (preg_match("/^Date: (.*)/", $lines[$i], $matches)) {
$date = $matches[1];
}
} else {
// not a header, but message
$message .= $lines[$i]."n";
}
#if (trim($lines[$i])=="") {
if ($i==45) {
// empty line, header section has ended
$splittingheaders = false;
}
}
mysql_close();
?>
You need attribute chmod 755
chmod 755 bounceforward.php
(*)
you need put your bounceforward.php in your shareannonce user folder !
you need put all your forward.php file for each domain in shareann user folder !
/home/shareannonce/ in this exemple in /etc/aliases
Install squirrelmail
cd /tmp
wget http://downloads.sourceforge.net/project/squirrelmail/stable/1.4.22/squirrelmail-webmail-1.4.22.zip
sudo unzip squirrelmail-webmail-1.4.22.zip
sudo mv squirrelmail-webmail-1.4.22/ /var/www/html/mail
sudo chown -R www-data:www-data /var/www/html/mail
sudo cp /var/www/html/mail/config/config_default.php /var/www/html/mail/config/config.php
sudo nano /var/www/html/mail/config/config.php
We need to set the values below:
$domain = 'yourwebsite.com'; => 'shareannonce.com'
$data_dir = '/var/www/html/mail/data/';
$attachment_dir = '/var/www/html/mail/attach/';
sudo mkdir /var/www/html/mail/attach/
sudo chown -R www-data:www-data /var/www/html/mail
Create boite mail virutalmin:
Choose the domain you would like to add the email account to. You can do that by selecting the domain name from the drop-down box on the top-left.
Click Edit Users.
Click Add a user to this server.
You can now enter the email address, full name, and password to use for this email account.
Click Create, and Virtualmin will add the email account to your server.
Go to SquirrelMail
http://IP_SERVER_X.X.X.X/mail/src/login.php