Тази статия е продължение на Подобрение SSL/TLS, Maildir, LMTP До тук имаме: ● инсталиран сървър за електронна поща бе защита от спам и вируси ● настроени PostFix и Dovecot за работа с пощенските кутии по стандарт Maildir ● PostFix и Dovecot работят взаимно един с друг ● PostFix и Dovecot работят със сертификати на Let's Encrypt ● удостоверяването в сървъра извършва Dovecot ● има дефиниран в сървъра филтър на съобщенията Sieve Какво не ни достига ● работим със домейни дефинирани в самата ОС, което е много неудобно ако имате пощи на много домейни ● работим с потребители на ОС и дефинирането на всеки потребител за кой домейн е много неудобно Как ще процедираме: ● ще създадем база данни в MySQL за пощенския сървър с потребители имащи право да работят върху нея ● ще конфигурираме PostFix и Dovecot да работят с базата ● ще тестваме работата на сървъра за електронна поща ● ще инсталираме приложение за управление на виртуалните домейни, потребители и т.н.
Както в предишната тема за Подобрение ВИРТУАЛИЗАЦИЯ без MySQL започваме с удостоверяването. За тази цел имахме Dovecot, който удостоверяваше и PostFix. Същевременно с това PostFix предоставяше на Dovecot да управлява пощенските кутии. И като заговорихме за удостоверяване на Dovecot, да погледнем как сме го дефинирали.
nano /etc/dovecot/conf.d/10-auth.conf ### Търсим за наличие на disable_plaintext_auth = yes disable_plaintext_auth = yes ### Търсим за наличие на auth_username_format = %n # auth_username_format = %n ### Търсим за наличие на auth_mechanisms = plain login auth_mechanisms = plain login ### Търсим за наличие на !include auth-system.conf.ext # !include auth-system.conf.ext !include auth-sql.conf.ext
disable_plaintext_auth = yes - предлага се на клиента да използва SSL/TLS, но не го задължава # auth_username_format = %n - забраняваме го защото при виртуализацията се ползва пълното име на клиента auth_mechanisms = plain login - задължаваме клиента да се удостоверява чрез протокол клиент/сървър (plain) и парала (login). # !include auth-system.conf.ext - забраняваме удостоверяване чрез системните потребители на операционната система !include auth-sql.conf.ext - удостоверяване чрез база данни на MySQL. И сега идва логичния въпрос. Как и къде да създаваме потребители с техните пароли? Това се дефинира чрез файла /etc/dovecot/conf.d/auth-sql.conf.ext. Отново имаме два варианта. Имаме константи UID, GID и пътя на пощенските кутии. Тези константи можем да ги дефинираме в auth-sql.conf.ext, или всичко да дефинираме чрез базата данни. По елегантния начин е втория, затова ще проиграем него.
nano /etc/dovecot/conf.d/auth-sql.conf.ext
passdb {
driver = sql
# Path for SQL configuration file, see example-config/dovecot-sql.conf.ext
args = /etc/dovecot/dovecot-sql.conf.ext
}
# "prefetch" user database means that the passdb already provided the
# needed information and there's no need to do a separate userdb lookup.
#
Забележете, дадени са и двата варианта за userdb. Може да се ползва driver = sql, пътя на пощенската кутия да е описан в базата или driver = static, твърдо да се укаже кое UID, GID ще ползваме както и пътя на пощенската кутия. Казахме ще работим чрез базата данни, затова нищо тук няма да променяме. args = /etc/dovecot/dovecot-sql.conf.ext ни задължава да редактираме този файл.
nano /etc/dovecot/dovecot-sql.conf.ext ### Най-отгоре driver = mysql connect = \ host=127.0.0.1 \ dbname=pfdb \ user=pfuser \ password=pfpass user_query = SELECT email as user, \ concat('*:bytes=', quota) AS quota_rule, \ '/var/vmail/%d/%n' AS home, \ 5000 AS uid, 5000 AS gid \ FROM virtual_users WHERE email='%u' password_query = SELECT password FROM virtual_users WHERE email='%u' iterate_query = SELECT email AS user FROM virtual_users
(\) означава, че командата продължава на следващия ред. Поглеждайки редакцията на файла произлизат няколко неща. Пъро е необходим потребител vmail с UID=5000, който да е член на групата vmail с GID=5000. Да го създадем.
groupadd -g 5000 vmail useradd -g vmail -u 5000 vmail -d /var/vmail -m
Забележете, UID=5000 и GID=5000. Ако тези номера са заети от друг потребител или група можете да ползвате дргуо ID, но то трябва да е по-голямо от 1000 Второто нещо което се набива на око е пътя на пощенската кутия. Той е /var/vmail/%d/%n и vmail:vmail трябва да има права върху кутиите.
chown -R vmail:vmail /var/vmail
Третото нещо което прави впечатление, е ползването на базата данни pfdb. Върху базата има право потребител pfuser с парола pfpass. Да създадем базата и потребителите които имат право да боравят с нея.
За начало ще създадем база от данни с прилежащите и таблици за да може виртуалните домейни, пощенски кутии, потребители и т.н. да се запишат вътре.
mysql create database pfdb; grant all on pfdb.* to 'pfadmin'@'localhost' identified by 'adminpass'; grant select on pfdb.* to 'pfuser'@'127.0.0.1' identified by 'pfpass'; quit
Създадохме база pfdb. Създадохме потребител pfadmin, който има пълни права върху базата. На практика това е потребителя-администратор. Създадохме и втори потребител, pfuser, който ще борави с таблиците на базата. Той ще е с ограничени права.
mysql USE pfdb; CREATE TABLE IF NOT EXISTS `virtual_domains` ( `id` int(11) NOT NULL auto_increment, `name` varchar(50) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; quit
mysql USE pfdb; CREATE TABLE IF NOT EXISTS `virtual_users` ( `id` int(11) NOT NULL auto_increment, `domain_id` int(11) NOT NULL, `email` varchar(100) NOT NULL, `password` varchar(150) NOT NULL, `quota` bigint(11) NOT NULL DEFAULT 0, PRIMARY KEY (`id`), UNIQUE KEY `email` (`email`), FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; quit
mysql USE pfdb; CREATE TABLE IF NOT EXISTS `virtual_aliases` ( `id` int(11) NOT NULL auto_increment, `domain_id` int(11) NOT NULL, `source` varchar(100) NOT NULL, `destination` varchar(100) NOT NULL, PRIMARY KEY (`id`), FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; quit
Да направим малко тестове. Първо да видим какво създадохме. Какви бази имаме:
mysql -u pfadmin -p Enter password: adminpass show databases; +------------------------------+ | Database | +------------------------------+ | information_schema | | pfdb | +------------------------------+ 2 rows in set (0.000 sec)
Забележете, pfadmin борави само с базите information_schema и pfdb. Да проверим сега какви таблици имаме в базата pfdb:
use pfdb; show tables; +-----------------------+ | Tables_in_pfdb | +-----------------------+ | virtual_aliases | | virtual_domains | | virtual_users | +-----------------------+ 3 rows in set (0.000 sec) quit
Имаме налични три таблици. ● virtual_aliases - виртуални псевдоними ● virtual_domains - виртуални домейни ● virtual_users - виртуални потребители
Генерираме парола за tachko@my.tlan.net.
doveadm pw -s BLF-CRYPT -u tachko@my.tlan.net Enter new password: Iceman Retype new password: Iceman {BLF-CRYPT}$2y$05$MiISIlQOprE98C/3GqQb9eVldMFlD7fLjRjxFoZ9Sf//ftJU1rqSm
Попълваме вече таблиците с данни. Забележете !!! Потребителите създаден в базата данни нямат нищо общо с тези които създадохме в ОС.
mysql REPLACE INTO pfdb.virtual_domains (id,name) VALUES ('1','my.tlan.net'); REPLACE INTO pfdb.virtual_users (id,domain_id,password,email) VALUES ('1', '1', '{BLF-CRYPT}$2y$05$MiISIlQOprE98C/3GqQb9eVldMFlD7fLjRjxFoZ9Sf//ftJU1rqSm', 'tachko@my.tlan.net'), ('2', '1', '{BLF-CRYPT}$2y$05$MiISIlQOprE98C/3GqQb9eVldMFlD7fLjRjxFoZ9Sf//ftJU1rqSm', 'cccp@my.tlan.net'); REPLACE INTO pfdb.virtual_aliases (id,domain_id,source,destination) VALUES ('1', '1', 'cccp@my.tlan.net', 'tachko@my.tlan.net'); quit
Да проверим какво попълнихме:
mysql -u pfadmin -p Enter password: adminpass use pfdb; select * from virtual_domains; +----+------------------+ | id | name | +----+------------------+ | 1 | my.tlan.net | +----+------------------+ select * from virtual_users; ============================================================================= | id | domain_id | email | password | quota | ============================================================================= | 1 | 1 | tachko@my.tlan.net | {BLF-CRYPT}$2y$05$Vrbxg6g.X..... | 0 | | 2 | 1 | cccp@my.tlan.net | {BLF-CRYPT}$2y$05$Vrbxg6g.X..... | 0 | select * from virtual_aliases; ==================================================== | id | domain_id | source | destination | ==================================================== | 1 | 1 | cccp@my.tlan.net | tachko@my.tlan.net | quit
Имаме инсталиран PostFix. За да работи с MySQL трябва да се инсталира и добавката за MySQL.
cd apt install postfix-mysql -y
Правим копие на конфигурационните файлове за PostFix, ако не сте направили по-рано.
cp /etc/postfix/main.cf /etc/postfix/main.cf.original cp /etc/postfix/master.cf /etc/postfix/master.cf.original
Сега да направим така, че PostFix да борави с базите на MySQL (MariaDB).
nano /etc/postfix/mysql-virtual-mailbox-domains.cf user = pfuser password = pfpass hosts = 127.0.0.1 dbname = pfdb query = SELECT 1 FROM virtual_domains WHERE name='%s' postconf virtual_mailbox_domains=mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf postmap -q my.tlan.net mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf 1
nano /etc/postfix/mysql-virtual-mailbox-maps.cf user = pfuser password = pfpass hosts = 127.0.0.1 dbname = pfdb query = SELECT 1 FROM virtual_users WHERE email='%s' postconf virtual_mailbox_maps=mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf postmap -q tachko@my.tlan.net mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf 1
nano /etc/postfix/mysql-virtual-alias-maps.cf user = pfuser password = pfpass hosts = 127.0.0.1 dbname = pfdb query = SELECT destination FROM virtual_aliases WHERE source='%s' postconf virtual_alias_maps=mysql:/etc/postfix/mysql-virtual-alias-maps.cf postmap -q cccp@my.tlan.net mysql:/etc/postfix/mysql-virtual-alias-maps.cf tachko@my.tlan.net
Има обаче един много важен момент. Примерно решавате всичко което идва до @my.tlan.net да се препраща до tachko@my.tlan.net. До тука добре. Това ще се изпълни, но тъй като @my.tlan.net е специфичен псевдоним той е с най-висок приоритет и това ще спре на практика пощата до другите потребители и само tachko@my.tlan.net ще получава поща. За да се избегне това се прави трик. Описват се в алиасите потребителите да получават поща до себе си -------------------------------------------------------------------------------------------------- Адрес Дестинация -------------------------------------------------------------------------------------------------- @my.tachko.com tachko@my.tlan.net tit@my.tlan.net tit@my.tlan.net Поради всичко това е нужно да създадем още един конфигурационен ред в /etc/postfix/main.cf., той на практика ще препокрие горният, който създадохме за виртуалните псевдоними.
nano /etc/postfix/mysql-email2email.cf user = pfuser password = pfpass hosts = 127.0.0.1 dbname = pfdb query = SELECT email FROM virtual_users WHERE email='%s' postconf virtual_alias_maps=mysql:/etc/postfix/mysql-virtual-alias-maps.cf,mysql:/etc/postfix/mysql-email2email.cf postmap -q tachko@my.tlan.net mysql:/etc/postfix/mysql-email2email.cf tachko@my.tlan.net
Уверете се, че само „root“ и „postfix“ потребителят могат да четат „.cf“ файловете – все пак паролата за вашата база данни се съхранява там:
chgrp postfix /etc/postfix/mysql-*.cf chmod u=rw,g=r,o= /etc/postfix/mysql-*.cf
Сега да проверим как работи PostFix.
telnet my.tlan.net 25
Trying 185.163.245.186...
Connected to my.tlan.net.
Escape character is '^]'.
220 ns1.my.tlan.net ESMTP Postfix (Debian/GNU)
ehlo my.tlan.net
250-ns1.my.tlan.net
250-PIPELINING
250-SIZE 50331648
250-VRFY
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250 CHUNKING
mail from:<cccp@my.tlan.net>
### Email sender adres
250 2.1.0 Ok
rcpt to:<tachkot@gmail.com>
### Email receiver adres
454 4.7.1
Имаме проблем. Този код за грешка се наблюдава в регистрационните файлове на сървъра, когато сървърът на получателя временно не може да получава имейли. В случая не знае дестинация my.tlan.net и не знае в коя мрежа да работи.
nano /etc/postfix/main.cf mydestination = $myhostname, ns1.my.tlan.net, my.tlan.net, localhost.my.tlan.net, , localhost mynetworks = 127.0.0.0/8 192.168.11.0/24 185.163.245.186/32 [::ffff:127.0.0.0]/104 [::1]/128
Да тестваме наново.
telnet my.tlan.net 25 Trying 185.163.245.186... Connected to my.tlan.net. Escape character is '^]'. 220 ns1.my.tlan.net ESMTP Postfix (Debian/GNU) ehlo my.tlan.net 250-ns1.my.tlan.net 250-PIPELINING 250-SIZE 50331648 250-VRFY 250-ETRN 250-STARTTLS 250-AUTH PLAIN LOGIN 250-ENHANCEDSTATUSCODES 250-8BITMIME 250-DSN 250 CHUNKING mail from:<tachko@my.tlan.net> 250 2.1.0 Ok rcpt to:<tachko@tachko.com> 250 2.1.5 Ok quit 221 2.0.0 Bye Connection closed by foreign host.
ВНИМАНИЕ !!! редакцията на mydestination е само за този тест. Ако не ползвахте виртуални домейни то mydestination трябваше да изглежда нещо от рода на:
mydestination = example.org, example.com, example.net, test.org
Никога не изброявайте домейните в mydestination при виртуалните домейни. Ползвайте пълното име на хоста на сървъра или просто задайте mydestination=localhost. Пример:
mydestination = $myhostname, localhost
Или най-вече:
mydestination = localhost
Виртуалните домейни се описват чрез virtual_mailbox_domains = example.org, example.com, a още по-добре в база данни както направихме по-рано с virtual_mailbox_domains=mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf. Да редактираме както трябва mydestination
nano /etc/postfix/main.cf # mydestination = $myhostname, ns1.my.tlan.net, my.tlan.net, localhost.my.tlan.net, , localhost mydestination = localhost
Започваме с инсталацията на липсващите модули.
apt install dovecot-mysql -y
Пълната конфигурация на Dovecot може да се види с:
doveconf -a
Много дълго за разглеждане. Можете примерно цялата конфигурация да я запишете във файл и да я разгледате с nano.
doveconf -a >> /home/cccp/dovecot.conf nano /home/cccp/dovecot.conf
Много е дълъг файла. Можете да отделите това което Ви вълнува с grep.
doveconf -a | grep mail_location mail_location = maildir:~/Maildir
Много полезен инструмент ползвайте го. Продължаваме с Dovecot. Запазваме оригиналните конфигурационни файлове, ако не сме ги запазили до сега.
cp /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf.original cp /etc/dovecot/conf.d/10-auth.conf /etc/dovecot/conf.d/10-auth.conf.original cp /etc/dovecot/conf.d/auth-sql.conf.ext /etc/dovecot/conf.d/auth-sql.conf.ext.original cp /etc/dovecot/conf.d/10-mail.conf /etc/dovecot/conf.d/10-mail.conf.original cp /etc/dovecot/conf.d/10-master.conf /etc/dovecot/conf.d/10-master.conf.original cp /etc/dovecot/conf.d/10-ssl.conf /etc/dovecot/conf.d/10-ssl.conf.original cp /etc/dovecot/conf.d/15-mailboxes.conf /etc/dovecot/conf.d/15-mailboxes.conf.original cp /etc/dovecot/dovecot-sql.conf.ext /etc/dovecot/dovecot-sql.conf.ext.original cp /etc/dovecot/conf.d/20-lmtp.conf /etc/dovecot/conf.d/20-lmtp.conf.origianal cp /etc/dovecot/conf.d/15-lda.conf /etc/dovecot/conf.d/15-lda.conf.original cp /etc/dovecot/conf.d/90-quota.conf /etc/dovecot/conf.d/90-quota.conf.original
Проверяваме местоположението на пощенските кутии във файла /etc/dovecot/dovecot-sql.conf.ext.
nano /etc/dovecot/conf.d/10-mail.conf # mail_location = mbox:~/mail:INBOX=/var/mail/%u mail_location = maildir:~/Maildir mail_plugins = quota
Фиксираме ограничения
chown root:root /etc/dovecot/dovecot-sql.conf.ext chmod go= /etc/dovecot/dovecot-sql.conf.ext
Рестартираме Dovecot.
systemctl restart dovecot
Да погледнем логовете.
cat /var/log/mail.log 2024-04-21T07:43:02.467432-04:00 ns1 dovecot: master: Warning: Killed with signal 15 (by pid=5698 uid=0 code=kill) 2024-04-21T07:43:03.574299-04:00 ns1 dovecot: log(5682): Warning: Killed with signal 15 (by pid=1 uid=0 code=kill) 2024-04-21T07:43:03.613287-04:00 ns1 dovecot: master: Dovecot v2.3.19.1 (9b53102964) starting up for imap, lmtp, sieve, pop3 (core dumps disabled) journalctl | grep imap Apr 20 00:25:42 my dovecot[18869]: master: Dovecot v2.3.19.1 (9b53102964) starting up for imap, lmtp, sieve, pop3 (core dumps disabled) journalctl -u dovecot
По същия начин и за Postfix
journalctl -u postfix Apr 19 23:56:37 my systemd[1]: Starting postfix.service - Postfix Mail Transport Agent... Apr 19 23:56:37 my systemd[1]: Finished postfix.service - Postfix Mail Transport Agent.
Работата с journalctl е доста неудобна но какво да се прави, това е тенденцията.
Проверяваме за наличието на:
nano /etc/dovecot/conf.d/10-master.conf service lmtp { # unix_listener lmtp { #mode = 0666 # } unix_listener /var/spool/postfix/private/dovecot-lmtp { group = postfix mode = 0600 user = postfix }
Рестартираме и проверяваме Dovecot.
systemctl restart dovecot systemctl status dovecot
nano /etc/postfix/main.cf # mailbox_transport = lmtp:unix:private/dovecot-lmtp virtual_transport = lmtp:unix:private/dovecot-lmtp
nano /etc/dovecot/conf.d/20-lmtp.conf protocol lmtp { # Space separated list of plugins to load (default is global mail_plugins). #mail_plugins = $mail_plugins mail_plugins = $mail_plugins quota sieve } systemctl restart dovecot systemctl status dovecot
По принцип сега трябва да покажа дефиниране на квоти, но за сега ще отложим тази задача. Първо ще пуснем сървъра да праща и получава писма, а след това ще го надграждаме.
За да тестваме по-нататък са ни необходими програмите swaks и mutt. Да ги инсталираме.
apt install swaks mutt -y
До тук трябва да има изградена структура на място където ще се разполагат писмата. Да проверим:
find /var/vmail
Има много папки със създадена структура Maildir за съхранение на писмата. Да проверим PostFix дали има грещки:
postfix check
Понякога се появяват следните грешки: “error: open database /etc/aliases.db: No such file or directory“? - изпълнете командата newaliases за да създадете нов машинен файл от псевдоними в /etc/aliases. “postfix/postfix-script: warning: symlink leaves directory: /etc/postfix/./makedefs.out“ - не обръщайте внимание на грешката, просто е бъг на Debian 12.
Отваряме втори терминал и в него пишем:
tail -f /var/log/mail.log
Така в реално време ще следим какво се записва в мейл лога. Да пробваме да пратим писмо през SWAKS през първия теминал.
swaks --server localhost --to tachko@my.tlan.net
Да проверим дали е пристигнало писмото използвайки IMAP протокола. За целта ще ползваме простия но много мощен IMAP клиент наречен mutt
mutt -f imaps://tachko@my.tlan.net@ns1.my.tlan.net Password for tachko@my.tlan.net@ns1.my.tlan.net: Iceman
Имаме две писма. Няма да обяснявам как се работи с програмата. Ако някой го вълнува може да се поразрови чрез Google. Навярно ще Ви е трудно да свикнете с програмата затова направете тестовете чрез IMAP WEB базиран клиент. Пратете/получете писмо, всичко би трябвало да работи нормално.
Квотите са ограничения на размера за потребителите. Можете да се уверите, че потребителите не губят произволно количество дисково пространство, а са принудени да почистват стари имейли от време на време. Какво се случва: ● Postfix трябва да отхвърля нови имейли, ако пощенската кутия на потребителя е над квотата. ● Dovecot трябва да следи квотата и колко потребителят вече е изразходвал от нея.
nano /etc/dovecot/conf.d/90-quota.conf ### Най-отгоре слагаме следното: plugin { quota = count:User quota quota_vsizes = yes quota_status_success = DUNNO quota_status_nouser = DUNNO quota_status_overquota = "452 4.2.2 Mailbox is full and cannot receive any more emails" } service quota-status { executable = /usr/lib/dovecot/quota-status -p postfix unix_listener /var/spool/postfix/private/quota-status { user = postfix } } systemctl restart dovecot
postconf smtpd_recipient_restrictions=reject_unauth_destination,"check_policy_service unix:private/quota-status"
Първо да ограничим размера на пощенската кутия на tachko@my.tlan.net на 5КВ.
mysql pfdb update virtual_users set quota=4000 where email='tachko@my.tlan.net'; quit
И самия тест:
swaks --server localhost --to tachko@my.tlan.net
Повторете изпращането на писма докато напълните кутията. Да си призная доста трябва да повторите операцията. По-лесния вариант е пращате от друг мейл писмо с прикачен файл по-голям от 5КВ. В резултат ще се получи следното съобщение във /var/log/mail.log:
2024-05-04T20:40:50.994052-04:00 ns1 postfix/smtpd[18212]: NOQUEUE: reject: RCPT from unknown[109.160.80.230]: 452 4.2.2 <tachko@my.tlan.net>: Recipient address rejected: Mailbox is full and cannot receive any more emails; from=<tachko@tachko.com> to=<tachko@my.tlan.net> proto=ESMTP helo=<mail.tachko.com>
Квотите работят, но потребителите трябва да са предупредени, че са надхвърлили лимита.
nano /etc/dovecot/conf.d/90-quota.conf plugin { quota = count:User quota quota_vsizes = yes quota_status_success = DUNNO quota_status_nouser = DUNNO quota_status_overquota = "452 4.2.2 Mailbox is full and cannot receive any more emails" } service quota-status { executable = /usr/lib/dovecot/quota-status -p postfix unix_listener /var/spool/postfix/private/quota-status { user = postfix } } plugin { quota_warning = storage=95%% quota-warning 95 %u quota_warning2 = storage=80%% quota-warning 80 %u } service quota-warning { executable = script /usr/local/bin/quota-warning.sh unix_listener quota-warning { user = vmail group = vmail mode = 0660 } }
За да работи плъгина се нуждаем от скрипт.
nano /usr/local/bin/quota-warning.sh #!/bin/sh PERCENT=$1 USER=$2 cat << EOF | /usr/lib/dovecot/dovecot-lda -d $USER -o "plugin/quota=maildir:User quota:noenforcing" From: postmaster@ns1.my.tlan.net Subject: Quota warning - $PERCENT% reached Your mailbox can only store a limited amount of emails. Currently it is $PERCENT% full. If you reach 100% then new emails cannot be stored. Thanks for your understanding. EOF chmod +x /usr/local/bin/quota-warning.sh systemctl restart dovecot
С това приключваме темата квоти. Имаме изграден сървър за електронна поща с използване на SQL база данни. От към защита и сигурност нещата доста куцат, но това в следващата статия.