Mail服務器: 基礎準備: postfix 發送 pop dovect imap postfixadmin 管理 MySQL 數據庫 apache/nginx PHP useradd -u 2000 -g 2000 apache centos7 操做 1、解壓MySQL tar zxvf mysql-5.7.19 #tar zxf mysql-5.7.19-linux-glibc2.12-x86_64.tar # tar zxf mysql-5.7.19-linux-glibc2.12-x86_64.tar.gz # tar zxf mysql-test-5.7.19-linux-glibc2.12-x86_64.tar.gz # mv mysql-5.7.19-linux-glibc2.12-x86_64 mysql # mkdir basedata basedir #useradd mysql #vim /etc/my.cnf [mysqld] datadir=/data/basedata basedir=/data/basedir socket=/var/lib/mysql/mysql.sock user=mysql # Disabling symbolic-links is recommended to prevent assorted security risks symbolic-links=0 [mysql-client] port = 3306 [mysqld_safe] log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid # chown -R mysql.mysql basedata/ # chown -R mysql.mysql basedir/ # chown -R mysql.mysql mysql # bin/mysqld --initialize --user=mysql --basedir=/data/basedir/ --datadir=/data/basedata/ [root@iZ88mizdnctZ mysql]# bin/mysqld_safe --user=mysql & 2017-10-09T06:40:40.028358Z mysqld_safe Logging to '/var/log/mysqld.log'. 2017-10-09T06:40:40.049500Z mysqld_safe Starting mysqld daemon with databases from /data/basedata 2017-10-09T06:40:40.565019Z mysqld_safe mysqld from pid file /var/run/mysqld/mysqld.pid ended [root@iZ88mizdnctZ mysql]# mkdir /var/run/mysqld [root@iZ88mizdnctZ mysql]# chown -R mysql.mysql /var/run/mysqld/ # bin/mysql -uroot -p --初始化密碼 mysql>alter user 'root'@'localhost' identified by 'mysql123'; mysql>flush privileges; # cp support-files/mysql.server /etc/init.d/mysqld 2、postfix安裝 #yum -y install httpd mysql mysql-devel mysql-server php php-pecl-Fileinfo php-mcrypt php-devel php-mysql php-common php-mbstring php-gd php-imap php-ldap php-odbc php-pear php-xml php-xmlrpc pcre pcre-devel #vim /etc/httpd/conf/httpd.conf AddType application/x-httpd-php .php PHPIniDir "/etc/php.ini" DirectoryIndex index.php index.html index.html.var # vim /var/www/html/index.php <?php phpinfo(); ?> #tar -zxvf postfixadmin-3.1.tar.gz -C /var/www/html/ #mv postfixadmin-3.1/ postfixadmin # vim config.inc.php $CONF['configured'] = true; $CONF['database_type'] = 'mysql'; $CONF['database_host'] = 'localhost'; $CONF['database_user'] = 'postfix'; $CONF['database_password'] = 'postfix'; $CONF['database_name'] = 'postfix'; $CONF['admin_email'] = 'postmaster@free.com'; $CONF['encrypt'] = 'dovecot:CRAM-MD5'; $CONF['dovecotpw'] = "/usr/bin/doveadm pw"; $CONF['domain_path'] = 'YES'; $CONF['domain_in_mailbox'] = 'NO'; $CONF['aliases'] = '1000'; $CONF['mailboxes'] = '1000'; $CONF['maxquota'] = '1000'; $CONF['fetchmail'] = 'NO'; $CONF['quota'] = 'YES'; $CONF['used_quotas'] = 'YES'; $CONF['new_quota_table'] = 'YES'; mysql> create database postfix; Query OK, 1 row affected (0.00 sec) mysql> create user postfix@localhost identified by 'postfixadmin'; Query OK, 0 rows affected (0.01 sec) mysql> grant all privileges on postfix.* to postfix@localhost identified by 'postfixadmin'; Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> flush privileges; Query OK, 0 rows affected (0.00 sec) mysql> commit -> ; Query OK, 0 rows affected (0.00 sec) dns配置 # vim /etc/named.conf options { listen-on port 53 { 172.24.17.62; }; listen-on-v6 port 53 { ::1; }; directory "/var/named"; dump-file "/var/named/data/cache_dump.db"; statistics-file "/var/named/data/named_stats.txt"; memstatistics-file "/var/named/data/named_mem_stats.txt"; allow-query { any; }; recursion yes; dnssec-enable yes; dnssec-validation yes; dnssec-lookaside auto; /* Path to ISC DLV key */ bindkeys-file "/etc/named.iscdlv.key"; }; logging { channel default_debug { file "data/named.run"; severity dynamic; }; }; zone "." IN { type hint; file "named.ca"; }; include "/etc/named.rfc1912.zones" #vim /etc/named.rfc1912.zones zone "dahan.org" IN { type master; file "dahan.org.zone"; allow-update { none; }; }; # vim /var/named/dahan.org.zone $TTL 1D @ IN SOA dahan.org. root.dahan.org. ( 0 ; serial 1D ; refresh 1H ; retry 1W ; expire 3H ) ; minimum IN NS ns.dahan.org. A 127.0.0.1 AAAA ::1 postfix IN A 172.24.17.62 ns IN A 172.24.17.62 Z88a04bir7Z IN A 172.24.17.62 postfixadmin配置 #tar -zxvf postfixadmin-3.1.tar.gz -C /var/www/html/ #cd /var/www/html #mv postfixadmin-3.1 postfixadmin # ll total 32 -rwxr-xr-x 1 root root 23834 Oct 11 15:23 config.inc.php -rwxrwxr-x 1 48 48 20 Oct 11 14:55 index.php drwxrwxr-x 16 apache apache 4096 Oct 13 11:06 postfixadmin #vim /var/www/html/postfixadmin/config.inc.php <?php /** * Postfix Admin * * LICENSE * This source file is subject to the GPL license that is bundled with * this package in the file LICENSE.TXT. * * * @version $Id$ * @license GNU GPL v2 or later. * * File: config.inc.php * Contains configuration options. */ /***************************************************************** * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * You have to set $CONF['configured'] = true; before the * application will run! * Doing this implies you have changed this file as required. * i.e. configuring database etc; specifying setup.php password etc. */ $CONF['configured'] = true; $CONF['setup_password'] = '{CRAM-MD5}f41aeb7fceda68c8d8ceaf23af5436253c60edddb62e6fb8ccec9b34c44be4e1'; $CONF['default_language'] = 'en'; $CONF['language_hook'] = ''; /* language_hook example function Called if $CONF['language_hook'] == '<name_of_the_function>' Allows to add or override $PALANG interface texts. If you add new texts, please always prefix them with 'x_' (for example $PALANG['x_mytext'] = 'foo') to avoid they clash with texts that might be added to languages/*.lang in future versions of PostfixAdmin. Please also make sure that all your added texts are included in all sections - that includes all 'case "XY":' sections and the 'default:' section (for users that don't have any of the languages specified in the 'case "XY":' section). Usually the 'default:' section should contain english text. If you modify an existing text/translation, please consider to report it can benefit from the corrected text/translation. Returns: modified $PALANG array */ /* function language_hook($PALANG, $language) { switch ($language) { case "de": $PALANG['x_whatever'] = 'foo'; break; case "fr": $PALANG['x_whatever'] = 'bar'; break; default: $PALANG['x_whatever'] = 'foobar'; } return $PALANG; } */ $CONF['database_type'] = 'mysqli'; $CONF['database_host'] = 'localhost'; $CONF['database_user'] = 'postfix'; $CONF['database_password'] = 'postfixadmin'; $CONF['database_name'] = 'postfix'; $CONF['database_prefix'] = ''; $CONF['database_tables'] = array ( 'admin' => 'admin', 'alias' => 'alias', 'alias_domain' => 'alias_domain', 'config' => 'config', 'domain' => 'domain', 'domain_admins' => 'domain_admins', 'fetchmail' => 'fetchmail', 'log' => 'log', 'mailbox' => 'mailbox', 'vacation' => 'vacation', 'vacation_notification' => 'vacation_notification', 'quota' => 'quota', 'quota2' => 'quota2', ); $CONF['admin_email'] = 'postfix@dahan.org'; $CONF['smtp_server'] = 'localhost'; $CONF['smtp_port'] = '25'; $CONF['smtp_client'] = ''; $CONF['encrypt'] = 'dovecot:CRAM-MD5'; $CONF['authlib_default_flavor'] = 'md5raw'; $CONF['dovecotpw'] = "/usr/bin/doveadm pw"; if(file_exists('/usr/bin/doveadm')) { $CONF['dovecotpw'] = "/usr/bin/doveadm pw"; # debian } $CONF['password_validation'] = array( '/.{5}/' => 'password_too_short 5', # minimum length 5 characters '/([a-zA-Z].*){3}/' => 'password_no_characters 3', # must contain at least 3 characters '/([0-9].*){2}/' => 'password_no_digits 2', # must contain at least 2 digits ); $CONF['generate_password'] = 'NO'; $CONF['show_password'] = 'NO'; $CONF['page_size'] = '10'; $CONF['default_aliases'] = array ( 'abuse' => 'abuse@change-this-to-your.domain.tld', 'hostmaster' => 'hostmaster@change-this-to-your.domain.tld', 'postmaster' => 'postmaster@change-this-to-your.domain.tld', 'webmaster' => 'webmaster@change-this-to-your.domain.tld' ); $CONF['domain_path'] = 'YES'; $CONF['domain_in_mailbox'] = 'NO'; $CONF['maildir_name_hook'] = 'NO'; /* maildir_name_hook example function Called when creating a mailbox if $CONF['maildir_name_hook'] == '<name_of_the_function>' - allows for customized maildir paths determined by a custom function - the example below will prepend a single-character directory to the beginning of the maildir, splitting domains more or less evenly over 36 directories for improved filesystem performance with large numbers of domains. Returns: maildir path ie. I/example.com/user/ */ /* function maildir_name_hook($domain, $user) { $chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; $dir_index = hexdec(substr(md5($domain), 28)) % strlen($chars); $dir = substr($chars, $dir_index, 1); return sprintf("%s/%s/%s/", $dir, $domain, $user); } */ /* *_struct_hook - change, add or remove fields If you need additional fields or want to change or remove existing fields, you can write a hook function to modify $struct in the *Handler classes. The edit form will automatically be updated according to the modified $struct. The list page is not yet updated automatically. You can define one hook function per class, named like the primary database table of that class. The hook function is called with $struct as parameter and must return the modified $struct. Note: Adding a field to $struct adds the handling of this field in PostfixAdmin, but it does not create it in the database. You have to do that yourself. Please follow the naming policy for custom database fields and tables on to avoid clashes with future versions of PostfixAdmin. See initStruct() in the *Handler class for the default $struct. See pacol() in functions.inc.php for the available flags on each column. Example: function x_struct_admin_modify($struct) { $struct['superadmin']['editable'] = 0; # make the 'superadmin' flag read-only $struct['superadmin']['display_in_form'] = 0; # don't display the 'superadmin' flag in edit form $struct['x_newfield'] = pacol( [...] ); # additional field 'x_newfield' return $struct; # important! } $CONF['admin_struct_hook'] = 'x_struct_admin_modify'; */ $CONF['admin_struct_hook'] = ''; $CONF['domain_struct_hook'] = ''; $CONF['alias_struct_hook'] = ''; $CONF['mailbox_struct_hook'] = ''; $CONF['alias_domain_struct_hook'] = ''; $CONF['fetchmail_struct_hook'] = ''; $CONF['aliases'] = '1000'; $CONF['mailboxes'] = '1000'; $CONF['maxquota'] = '1000'; $CONF['domain_quota_default'] = '2048'; $CONF['quota'] = 'YES'; $CONF['domain_quota'] = 'YES'; $CONF['quota_multiplier'] = '1024000'; $CONF['transport'] = 'NO'; $CONF['transport_options'] = array ( ); $CONF['transport_default'] = 'virtual'; $CONF['vacation'] = 'NO'; $CONF['vacation_domain'] = 'autoreply.change-this-to-your.domain.tld'; $CONF['vacation_control'] ='YES'; $CONF['vacation_control_admin'] = 'YES'; $CONF['vacation_choice_of_reply'] = array ( # considered annoying - only send a reply on every mail if you really need it ); $CONF['alias_control'] = 'YES'; $CONF['alias_control_admin'] = 'YES'; $CONF['special_alias_control'] = 'NO'; $CONF['alias_goto_limit'] = '0'; $CONF['alias_domain'] = 'YES'; $CONF['backup'] = 'NO'; $CONF['sendmail'] = 'YES'; $CONF['sendmail_all_admins'] = 'NO'; $CONF['logging'] = 'YES'; $CONF['fetchmail'] = 'NO'; $CONF['fetchmail_extra_options'] = 'NO'; $CONF['show_header_text'] = 'NO'; $CONF['header_text'] = ':: Postfix Admin ::'; $CONF['show_footer_text'] = 'YES'; $CONF['footer_text'] = 'Return to change-this-to-your.domain.tld'; $CONF['motd_user'] = ''; $CONF['motd_admin'] = ''; $CONF['motd_superadmin'] = ''; $CONF['welcome_text'] = <<<EOM Hi, Welcome to your new account. EOM; $CONF['emailcheck_resolve_domain']='YES'; $CONF['show_status']='YES'; $CONF['show_status_key']='YES'; $CONF['show_status_text']=' '; $CONF['show_undeliverable']='YES'; $CONF['show_undeliverable_color']='tomato'; $CONF['show_undeliverable_exceptions']=array("unixmail.domain.ext","exchangeserver.domain.ext"); $CONF['show_popimap']='YES'; $CONF['show_popimap_color']='darkgrey'; $CONF['show_custom_domains']=array("subdomain.domain.ext","domain2.ext"); $CONF['show_custom_colors']=array("lightgreen","lightblue"); $CONF['recipient_delimiter'] = ""; $CONF['mailbox_postcreation_script'] = ''; $CONF['mailbox_postedit_script'] = ''; $CONF['mailbox_postdeletion_script'] = ''; $CONF['domain_postcreation_script'] = ''; $CONF['domain_postdeletion_script'] = ''; $CONF['create_mailbox_subdirs'] = array(); $CONF['create_mailbox_subdirs_host']='localhost'; $CONF['create_mailbox_subdirs_prefix']='INBOX.'; $CONF['used_quotas'] = 'YES'; $CONF['new_quota_table'] = 'YES'; $CONF['create_mailbox_subdirs_hostoptions'] = array(); $CONF['theme_logo'] = 'images/logo-default.png'; $CONF['theme_css'] = 'css/default.css'; $CONF['theme_custom_css'] = ''; $CONF['xmlrpc_enabled'] = false; if (file_exists(dirname(__FILE__) . '/config.local.php')) { require_once(dirname(__FILE__) . '/config.local.php'); } /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ ip/setup.php ip/login.php postfix配置 # vim /etc/postfix/main.cf queue_directory = /var/spool/postfix command_directory = /usr/sbin daemon_directory = /usr/libexec/postfix data_directory = /var/lib/postfix mail_owner = postfix myhostname = postfix.dahan.org mydomain = dahan.org myorigin = $mydomain inet_interfaces = all inet_protocols = ipv4 mydestination = localhost unknown_local_recipient_reject_code = 550 mynetworks_style = host mynetworks = 0.0.0.0/0,127.0.0.0/8 alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliases debug_peer_level = 2 debugger_command = PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin ddd $daemon_directory/$process_name $process_id & sleep 5 sendmail_path = /usr/sbin/sendmail.postfix newaliases_path = /usr/bin/newaliases.postfix mailq_path = /usr/bin/mailq.postfix setgid_group = postdrop html_directory = no manpage_directory = /usr/share/man sample_directory = /usr/share/doc/postfix-2.6.6/samples readme_directory = /usr/share/doc/postfix-2.6.6/README_FILES virtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql_virtual_domains_maps.cf virtual_alias_maps = proxy:mysql:/etc/postfix/mysql_virtual_alias_maps.cf virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf virtual_create_maildirsize = yes virtual_mailbox_extended = yes virtual_mailbox_limit_maps = mysql:/etc/postfix/mysql_virtual_mailbox_limit_maps.cf virtual_mailbox_limit_override = yes virtual_maildir_limit_message = Sorry, this user has exceeded their disk space quota, please try again later. virtual_overquota_bounce = yes virtual_uid_maps = static:2000 virtual_gid_maps = static:2000 proxy_read_maps = $local_recipient_maps $mydestination $virtual_alias_maps $virtual_alias_domains $virtual_mailbox_maps $virtual_mailbox_domains $relay_recipient_maps $relay_domains $canonical_maps $sender_canonical_maps $recipient_canonical_maps $relocated_maps $transport_maps $mynetworks $virtual_mailbox_limit_maps smtpd_sasl_auth_enable = yes smtpd_sasl_type = dovecot smtpd_sasl_path = /var/run/dovecot/auth-client smtpd_sasl_security_options = noanonymous broken_sasl_auth_clients = yes smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_invalid_hostname, reject_non_fqdn_hostname, reject_unknown_sender_domain, reject_non_fqdn_sender, reject_non_fqdn_recipient, reject_unknown_recipient_domain, reject_unauth_pipelining, reject_unauth_destination virtual_transport = dovecot dovecot_destination_recipient_limit = 1 disable_dns_lookups = yes #vim /etc/postfix/mysql_virtual_domains_maps.cf user = postfix password = postfixadmin hosts = localhost dbname = postfix query = SELECT domain FROM domain WHERE domain='%s' AND active = '1' #cat /etc/postfix/mysql_virtual_alias_maps.cf |grep -v "^#"|grep -v "^$" user = postfix password = postfixadmin hosts = localhost dbname = postfix query = SELECT goto FROM alias WHERE address='%s' AND active = '1' # cat /etc/postfix/mysql_virtual_mailbox_maps.cf |grep -v "^#"|grep -v "^$" user = postfix password = postfixadmin hosts = localhost dbname = postfix query = SELECT CONCAT(domain,'/',maildir) FROM mailbox WHERE username='%s' AND active = '1' # cat /etc/postfix/mysql_virtual_mailbox_limit_maps.cf |grep -v "^#"|grep -v "^$" user = postfix password = postfixadmin hosts = localhost dbname = postfix query = SELECT quota FROM mailbox WHERE username='%s' AND active = '1' # postconf -a cyrus dovecot dovecot配置 # cat /etc/dovecot/dovecot.conf |grep -v "^#"|grep -v "^$" protocols = imap pop3 listen = * dict { #quota = mysql:/etc/dovecot/dovecot-dict-sql.conf.ext quota = mysql:/etc/dovecot/dovecot-dict-sql.conf.ext #expire = sqlite:/etc/dovecot/dovecot-dict-sql.conf.ext } !include conf.d/*.conf # cat /etc/dovecot/conf.d/10-mail.conf |grep -v "#"|grep -v "^$" mail_location = maildir:%hMaildir mbox_write_locks = fcntl # cat /etc/dovecot/conf.d/10-master.conf |grep -v "#"|grep -v "^$" service imap-login { inet_listener imap { } inet_listener imaps { } } service pop3-login { inet_listener pop3 { } inet_listener pop3s { } } service lmtp { unix_listener lmtp { } } service imap { } service pop3 { } service auth { unix_listener auth-userdb { mode = 0600 user = apache group = apache } unix_listener auth-client { mode = 0600 user = postfix group = postfix } } service auth-worker { } service dict { unix_listener dict { mode = 0600 user = apache group = apache } } # cat /etc/dovecot/conf.d/15-lda.conf |grep -v "#"|grep -v "^$" protocol lda { mail_plugins = quota postmaster_address = postmaster@dahan.org } # cat /etc/dovecot/conf.d/20-imap.conf |grep -v "#"|grep -v "^$" protocol imap { mail_plugins = quota imap_quota } # cat /etc/dovecot/conf.d/20-pop3.conf |grep -v "#"|grep -v "^$" protocol pop3 { pop3_uidl_format = %08Xu%08Xv mail_plugins = quota } # cat /etc/dovecot/conf.d/90-quota.conf |grep -v "#"|grep -v "^$" plugin { quota_rule = *:storage=1G } plugin { } plugin { quota = dict:User quota::proxy::quota } plugin { } # cat /etc/dovecot/dovecot-sql.conf.ext |grep -v "#"|grep -v "^$" driver = mysql connect = host=localhost dbname=postfix user=postfix password=postfixadmin default_pass_scheme = CRAM-MD5 user_query = SELECT CONCAT('/var/vmail/', maildir) AS home, 2000 AS uid, 2000 AS gid, CONCAT('*:bytes=', quota) as quota_rule FROM mailbox WHERE username = '%u' AND active='1' password_query = SELECT username AS user, password, CONCAT('/var/vmail/', maildir) AS userdb_home, 2000 AS userdb_uid, 2000 AS userdb_gid, CONCAT('*:bytes=', quota) as userdb_quota_rule FROM mailbox WHERE username = '%u' AND active='1' # cat /etc/dovecot/dovecot-dict-sql.conf.ext |grep -v "#"|grep -v "^$" connect = host=localhost dbname=postfix user=postfix password=postfixadmin map { pattern = priv/quota/storage table = quota2 username_field = username value_field = bytes } map { pattern = priv/quota/messages table = quota2 username_field = username value_field = messages } # service postfix start # service dovecot start