Postfix отклоняет вложение меньше разрешённого размера: где теряются мегабайты и какой запас закладывать в message_size_limit
Классика жанра: инженер-проектировщик отправляет заказчику PDF-комплект раздела на 19 мегабайт, в настройках сервера стоит «25 мегабайт», а письмо возвращается с ошибкой про превышение размера. Дальше обычно происходит худшее — админ ставит лимит «с запасом, чтобы больше не жаловались», и через час встаёт вся доставка. В статье разбираю арифметику MIME (почему файл на проводе весит в 1,37 раза больше), три разных места, где Postfix отбивает письмо по размеру, разбор на примере инжиниринговой компании на 20 рабочих мест, лимиты Dovecot/Rspamd/веб-почты и внешних сервисов и рабочие цифры для main.cf.
Куда деваются мегабайты: файл на диске и письмо на проводе — это разные размеры
Первое, что нужно принять: message_size_limit в Postfix — это не «размер вложения». Это максимальный размер всего сообщения в байтах, включая информацию конверта, — так и написано в postconf(5). То есть в лимит укладываются: заголовки (а их к моменту приёма уже прилично — Received от каждого хопа, DKIM-Signature, ARC, Message-ID, Content-Type с границами), текст письма, подпись с картинкой-логотипом, и уже потом — само вложение, но не в том виде, в каком оно лежит на диске.
Вложение едет по SMTP закодированным в Base64. По RFC 2045, раздел 6.8, три входных октета превращаются в четыре символа, то есть данные раздуваются примерно на 33 процента — в тексте RFC так и сказано: «The encoded data are consistently only about 33 percent larger than the unencoded data». И это ещё не всё. Тот же раздел требует, чтобы закодированный поток разбивался на строки не длиннее 76 символов, а каждый перевод строки в SMTP — это два байта CRLF. Итого на каждые 76 символов добавляется ещё 2 — плюс примерно 2,6 процента сверху.
Перемножаем: 4/3 × 78/76 ≈ 1,368. Округляю до 1,37 — это и есть коэффициент, на который я умножаю размер файла, когда прикидываю, пролезет ли письмо. Файл на 19 МБ (19 922 944 байта) на проводе весит около 27,3 млн байт. При лимите «25 мегабайт», который админ записал как 26214400 (это 25 МиБ, то есть 26,2 млн байт), письмо не проходит — не хватает около мегабайта, и это ещё без заголовков. Файл на 18 МБ, к слову, пролезает с запасом всего около 380 КБ — ровно до первой подписи с логотипом или пересылки с цитатой. Отсюда и вечное недоумение: «файл же меньше лимита».
Есть и мелочи, которые добивают. Текстовая часть письма в quoted-printable раздувается на кириллице почти втрое (каждая русская буква — это =D0=BF, шесть символов вместо двух байт). Корпоративная подпись с логотипом — это ещё один MIME-part, тоже в Base64. Пересланное письмо (message/rfc822) тащит внутри всю предыдущую цепочку заголовков. Поэтому в расчёте я всегда добавляю к результату мегабайт-полтора «на накладные».
- Base64: +33 % (4 символа на каждые 3 байта), RFC 2045 §6.8
- Перенос строк каждые 76 символов + CRLF: ещё около +2,6 %
- Итоговый практический коэффициент: ×1,37
- Заголовки, MIME-границы, подпись с картинкой: +0,5…1,5 МБ
- Файл 19 МиБ → около 27,3 млн байт на проводе; файл 25 МиБ → около 35,9 млн байт
Три места, где Postfix отбивает письмо по размеру, и три разных лога
Почти вся путаница в диагностике идёт от того, что проверок размера в Postfix несколько, и выглядят они в логе по-разному. Первая срабатывает ещё на команде MAIL FROM, если клиент по RFC 1870 сам объявил размер: MAIL FROM:<user@example.com> SIZE=31457280. Функция smtpd_check_size() в исходниках сравнивает объявленное значение с message_size_limit и отдаёт 552 5.3.4 Message size exceeds fixed limit. Это хороший сценарий: письмо не уехало вообще, тело не передавалось, пользователь получил отказ мгновенно.
Вторая проверка — по ходу приёма данных, в самом smtpd. Если клиент размер не объявил (а так делают многие мобильные клиенты и самописные скрипты), сервер честно принимает поток и считает байты. Как только счётчик упирается в лимит, в maillog падает предупреждение queue file size limit exceeded, а после конца DATA клиент получает 552 5.3.4 Error: message file too big. Текст берётся из общей таблицы статусов cleanup (global/cleanup_strerror.c, код CLEANUP_STAT_SIZE), поэтому та же формулировка встречается и в отказах самого cleanup(8). Симптом характерный: пользователь минуту грузил вложение по узкому каналу, и только потом получил отказ.
Третья проверка вообще не про размер письма, а про место на диске, и именно она рушит почту целиком. Начиная с Postfix 2.1 SMTP-сервер отвергает MAIL FROM, если свободного места в файловой системе очереди меньше, чем 1,5 × message_size_limit. Коэффициент задан в smtpd_check.c переменной smtpd_space_multf = 1.5. Клиент получает 452 4.3.1 Insufficient system storage, а в лог сервера падает not enough free space in mail queue: N bytes < 1.5*message size limit. Обратите внимание: отбиваются ВСЕ письма, а не только крупные. Одно неаккуратное увеличение лимита на разделе с малым запасом — и приём почты встал.
Практический алгоритм разбора у меня такой — три грепа по логу, и картина ясна:
# 1) отказ по объявленному размеру (письмо даже не начало передаваться)
grep -E '552 5\.3\.4' /var/log/mail.log
# 2) обрыв по ходу приёма / cleanup
grep -E 'queue file size limit exceeded|message file too big' /var/log/mail.log
# 3) нет места в очереди — отбивается вся входящая почта
grep -E '452 4\.3\.1|not enough free space in mail queue' /var/log/mail.log
# что вообще настроено
postconf message_size_limit mailbox_size_limit virtual_mailbox_limit queue_minfree
df -h /var/spool/postfix- 552 5.3.4 Message size exceeds fixed limit — отказ на MAIL FROM по объявленному SIZE=
- 552 5.3.4 Error: message file too big + warning «queue file size limit exceeded» — обрыв по ходу приёма
- 452 4.3.1 Insufficient system storage — мало места в очереди, режется вся почта
- Если 552 приходит от чужого сервера в bounce — лимит не ваш, а получателя
Разбор из практики: «Инженерный контур», 20 рабочих мест, почта встала на два часа
Стенд: Debian 12, Postfix из репозитория дистрибутива (ветка 3.7), связка с Dovecot, доставка через virtual(8) в Maildir, около 25 ящиков (20 сотрудников плюс общие tender@ и pto@), свой сервер в стойке. Заявка от инжиниринговой компании «Инженерный контур» звучала так: «ГИПы не могут отправить заказчику комплект проектной документации, хотя айтишник ставил лимит 25 мегабайт». В main.cf действительно стояло message_size_limit = 26214400. Проектировщик отправлял сшитый PDF раздела АР на 22 МБ (23 068 672 байта). Считаем: 23 068 672 × 1,37 ≈ 31,6 МБ, плюс подпись с логотипом и три Received — около 31,8 МБ. Против лимита в 26,2 МБ. Отказ был мгновенный, 552 5.3.4 Message size exceeds fixed limit — Outlook объявлял SIZE честно.
Дальше классика, которую я вижу из раза в раз. До меня коллега решил проблему «с запасом»: поставил message_size_limit = 78643200 и сделал postfix reload. Через минуту почта перестала доставляться в ящики совсем — письма копились в active-очереди. В логе: fatal: configuration error: virtual_mailbox_limit is smaller than message_size_limit, агент доставки virtual(8) падал на старте и рестартовал по кругу. Причина в самом коде агента: если virtual_mailbox_limit (по умолчанию 51200000) меньше лимита сообщения, процесс завершается msg_fatal и не работает вообще. Ровно то же поведение у local(8) с mailbox_size_limit. Это не «предупреждение в логе» — это отказ доставки.
Починили лимиты — вылезло следующее. Раздел /var/spool на этом сервере был отдельный, 20 ГБ, и почти весь его съел забытый дамп базы архива чертежей. Свободно оставалось около 300 МБ. При старом лимите требование было 1,5 × 26 214 400 ≈ 39 МБ, после того как коллега поднял лимит до 75 МБ — уже 1,5 × 78 643 200 ≈ 118 МБ. Пока virtual(8) лежал, недоставленные письма с вложениями копились в очереди на том же разделе, свободное место за полтора часа упало ниже 118 МБ, и весь входящий поток начал отбиваться 452 4.3.1 Insufficient system storage. Внешние отправители этого почти не заметили — их серверы повторяли попытки, — но двое заказчиков успели позвонить и сказать «ваша почта не принимает».
Чем закончилось. Я поставил message_size_limit = 52428800 (50 МБ, то есть реальный потолок вложения около 36 МБ), лимиты почтовых файлов снял (mailbox_size_limit = 0, virtual_mailbox_limit = 0 — квоты у них и так считает Dovecot), явно задал queue_minfree = 157286400 (150 МБ, это 3 × лимит — с запасом), вычистил дамп и добавил в мониторинг проверку свободного места на разделе очереди. Отдельно договорились с руководством, что комплекты чертежей тяжелее 35 МБ уходят заказчикам ссылкой на файловое хранилище, а не вложением. За следующие четыре месяца — ни одного возврата по размеру; две попытки отправить архив DWG на 60 МБ отбились сразу на MAIL FROM, с внятным текстом ошибки в Outlook, а не «через минуту после отправки».
- Было: message_size_limit = 26214400, файл 22 МБ → на проводе 31,8 МБ → 552 5.3.4
- Сделали «с запасом» 78643200 → virtual(8) падает fatal, доставка стоит
- Раздел очереди 20 ГБ, свободно около 300 МБ и очередь растёт → 452 4.3.1 на весь входящий поток
- Стало: 52428800 + mailbox/virtual limits = 0 + queue_minfree = 157286400 + мониторинг диска
Сколько ставить: считаем от потребности, а не «побольше»
Я иду от простого вопроса заказчику: какой самый большой файл реально нужно отправлять письмом? Не «а вдруг когда-нибудь», а по факту прошлого года. Обычно ответ — скан пакета документов на 15–25 МБ. Дальше формула: лимит = размер файла × 1,4 + 2 МБ на заголовки и подпись, округлить вверх до круглого числа. Для 25 МБ получается 37 МБ, ставлю 41943040 (40 МБ) или 52428800 (50 МБ), если хочется спать спокойно.
Ставить 200–500 МБ бессмысленно, и вот почему. Письмо принимает не только ваш сервер. По официальным справкам: письмо на ящик Яндекса не должно превышать 30 МБ вместе с вложениями, в Gmail для личных аккаунтов предел вложений 25 МБ, в VK Почте (Mail.ru) — 25 МБ на файл, всё крупнее веб-интерфейсы этих сервисов превращают в ссылку на облако. У корпоративных серверов получателей потолок свой, и узнать его можно только по SIZE в ответе на EHLO. Вы можете принять у своего пользователя гигантское письмо, поставить его в очередь, потратить канал — и получить 552 от чужого MX через минуту, только теперь это будет отложенный bounce, который пользователь прочитает не сразу. Хуже, чем честный отказ на этапе отправки.
Прежде чем обещать пользователю «теперь пройдёт», проверяю потолок принимающей стороны — сервер объявляет его в ответе на EHLO ключевым словом SIZE (RFC 1870). Это тридцать секунд работы:
# что объявляет наш сервер
swaks --server mail.example.com --quit-after=EHLO | grep -i size
# что объявляет MX получателя
MX=$(dig +short mx partner.example | sort -n | head -1 | awk '{print $2}')
swaks --server "$MX" --quit-after=EHLO | grep -i size
# без swaks, руками
openssl s_client -connect mail.example.com:25 -starttls smtp -crlf
# EHLO test.example.com → смотрим строку 250-SIZE 52428800Ещё одна деталь про запас снизу. В postconf(5) есть отдельное предупреждение к message_size_limit: будьте осторожны с изменениями, слишком маленькие значения приводят к потере уведомлений о недоставке, когда размер bounce-сообщения превышает лимит локальной или удалённой стороны. То есть жадный лимит в 2–3 МБ — это не только злые пользователи, но и молча пропадающие отчёты о недоставке. Ниже 10 МБ по умолчанию я не опускаюсь никогда.
- Файл 10 МБ → message_size_limit 15–16 МБ (16777216)
- Файл 20 МБ → 30–32 МБ (33554432)
- Файл 25 МБ → 37–40 МБ (41943040)
- Файл 50 МБ → 73–80 МБ (83886080) и обязательно проверка стороны получателя
- Значение 0 = «без лимита» — не использовать на боевом сервере
Что тянется следом: лимиты файлов, место в очереди и before-queue фильтры
Изменение одного параметра почти всегда требует правки ещё двух-трёх. Первое — лимиты размера почтового файла. mailbox_size_limit (по умолчанию 51200000) ограничивает размер любого mbox- или maildir-файла, в который пишет local(8), причём в мануале прямо сказано: этот лимит не должен быть меньше лимита сообщения. У virtual(8) свой параметр — virtual_mailbox_limit, тоже 51200000 по умолчанию. Ноль отключает ограничение. Если вы отдаёте квотирование Dovecot (а в 2026 году так делают почти все), обнуляйте оба и не плодите две системы квот.
Второе — место. Требование «свободно ≥ 1,5 × message_size_limit» действует всегда, даже если вы не трогали queue_minfree (его дефолт — 0, что означает «использовать правило 1,5 ×»). Если задаёте queue_minfree явно, задавайте не меньше полутора лимитов, иначе Postfix при старте напишет в лог предупреждение вида queue_minfree(N) should be at least 1.5*message_size_limit(M) — эта проверка тоже есть в исходниках smtpd. Я обычно ставлю 3× и добавляю алерт мониторинга на 10 % свободного места на разделе очереди.
Третье — before-queue фильтры. Если у вас настроен smtpd_proxy_filter с опцией speed_adjust (антиспам/антивирус до постановки в очередь), Postfix сохраняет письмо во временный файл, и в документации отдельно отмечено: эта возможность увеличивает минимально необходимый объём свободного места ещё на один message_size_limit. В комментарии в smtpd.c разработчики прямо пишут, что в этом режиме требование к свободному месту поднимается до 2,5 × message_size_limit. На маленьком разделе очереди с большим лимитом это ощутимо.
Минимальный рабочий блок в main.cf, который я кладу на типовой сервер до 50 ящиков, выглядит так:
# 50 МБ на письмо → около 36 МБ полезного вложения
message_size_limit = 52428800
# квоты считает Dovecot, файловые лимиты Postfix отключаем
mailbox_size_limit = 0
virtual_mailbox_limit = 0
# явный минимум свободного места: 3 × лимит
queue_minfree = 157286400- mailbox_size_limit (default 51200000) — для local(8), не может быть меньше message_size_limit
- virtual_mailbox_limit (default 51200000) — то же для virtual(8)
- queue_minfree (default 0) — при явной установке минимум 1,5 × message_size_limit
- smtpd_proxy_options = speed_adjust — плюс ещё один message_size_limit свободного места
Postfix пропустил, а дальше? Лимиты Dovecot LMTP, Rspamd, веб-почты и чужих серверов
После того как smtpd принял письмо, оно проходит ещё несколько звеньев, и у каждого свой потолок. Самый коварный — Dovecot. В ветке 2.3 есть параметр плагина квот quota_max_mail_size (появился в 2.2.29, по умолчанию 0, то есть без ограничения): максимальный размер письма, которое можно сохранить через LMTP, IMAP APPEND или doveadm save. В Dovecot 2.4 он называется quota_mail_size и объявляется LMTP-клиентам через расширение SIZE, а IMAP-клиентам — через APPENDLIMIT. Если он меньше message_size_limit, Postfix письмо примет, поставит в очередь, а при доставке по LMTP получит отказ — и пользователь увидит bounce уже от собственного сервера. Документация Dovecot прямо советует держать этот параметр примерно равным максимальному размеру письма на MTA; я ставлю его чуть больше лимита Postfix.
Второе звено — антиспам. У Rspamd параметр max_message в общих опциях задаёт максимальный размер письма, которое он вообще будет сканировать, по умолчанию 50 МБ. Письмо крупнее не отбивается, а просто не проверяется, и если вы подняли лимит Postfix до 80 МБ, самые тяжёлые вложения — как раз те, где любят прятать вредоносные макросы, — уходят в ящики без проверки. У ClamAV отдельно ограничены MaxScanSize и MaxFileSize. Поднимая лимит письма, я всегда поднимаю и эти значения, иначе получается дыра, о которой никто не знает.
Третье — веб-почта, и здесь ошибка выглядит совсем иначе: не 552, а 413 Request Entity Too Large от nginx или молча оборванная загрузка. У nginx client_max_body_size по умолчанию всего 1 МБ, у PHP upload_max_filesize — 2 МБ, post_max_size — 8 МБ. В Roundcube есть собственный $config['max_message_size'] (в defaults.inc.php — '100M'), и в комментарии к нему честно написано, что SMTP-сервер может использовать другое значение. Учтите, что веб-почта сравнивает с лимитом исходный файл, а Postfix — письмо после Base64, так что при одинаковых цифрах Roundcube пропустит вложение, которое потом отобьёт smtpd.
Минимальный согласованный набор для лимита 50 МиБ в Postfix у меня выглядит так:
# Dovecot 2.3: conf.d/90-quota.conf
plugin {
quota_max_mail_size = 60M
}
# Dovecot 2.4: тот же смысл, новое имя
# quota_mail_size = 60M
# Rspamd: local.d/options.inc (в байтах)
max_message = 62914560;
# nginx перед веб-почтой
client_max_body_size 64m;
# php.ini для веб-почты
upload_max_filesize = 40M
post_max_size = 64M
# Roundcube: config/config.inc.php — порог по исходному файлу с учётом Base64
$config['max_message_size'] = '36M';Последнее звено — сервер получателя, на который вы не влияете. Для инжиниринговой компании это обычно не абстракция: заказчики сидят на Яндекс 360, на VK WorkSpace или на своих Exchange. По официальным справкам письмо на ящик Яндекса не должно превышать 30 МБ вместе с вложениями, личный Gmail принимает к отправке вложения до 25 МБ, VK Почта — файлы до 25 МБ, а всё крупнее их веб-интерфейсы превращают в ссылку на облако. Для SMTP-трафика между серверами истина одна — SIZE в ответе на EHLO у MX получателя, и проверять его нужно до того, как пообещать ГИПу, что «50 МБ теперь уйдут кому угодно».
- Dovecot 2.3 `quota_max_mail_size` / 2.4 `quota_mail_size` — не меньше message_size_limit, иначе отказ на LMTP и bounce от своего сервера
- Rspamd `max_message` (по умолчанию 50 МБ) и ClamAV `MaxScanSize`/`MaxFileSize` — выше лимита письма, иначе крупные письма идут без проверки
- nginx `client_max_body_size` (1 МБ по умолчанию) и PHP `upload_max_filesize`/`post_max_size` — причина 413 в веб-почте
- Roundcube `max_message_size` — ставить с поправкой на Base64, то есть около message_size_limit / 1,4
- Внешние сервисы: Яндекс — до 30 МБ на письмо, Gmail и VK Почта — 25 МБ на вложения; для серверов — SIZE в EHLO
Как менять правильно: команды, per-service overrides и особенности готовых сборок
Руками main.cf я не редактирую — только postconf -e: он аккуратно заменяет существующую строку, а не дописывает дубль в конец файла. Имя параметра он при этом не проверяет, опечатку запишет как есть, поэтому после правки я всегда смотрю postconf -n — неизвестный параметр Postfix отметит предупреждением unused parameter. Дальше reload (не restart: reload не рвёт текущие сессии) и обязательная проверка того, что реально применилось, потому что параметр может быть переопределён в master.cf для конкретного сервиса:
postconf -e 'message_size_limit = 52428800'
postconf -e 'mailbox_size_limit = 0'
postconf -e 'virtual_mailbox_limit = 0'
postconf -e 'queue_minfree = 157286400'
postfix check && postfix reload
# что стало (и что вообще отличается от дефолтов)
postconf -n | grep -E 'size_limit|minfree'
# переопределения по сервисам
postconf -M | grep -n 'message_size_limit'Разные лимиты для приёма снаружи и для отправки своими сотрудниками — рабочий приём. Своим на submission (587) можно дать больше, чем анонимному потоку на 25 порт. Делается это оверрайдом в master.cf. Только помните: письмо после smtpd попадает в cleanup(8), и лимит для очереди применяет именно он, поэтому для по-настоящему разных лимитов нужен и отдельный сервис cleanup:
# master.cf
submission inet n - y - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o message_size_limit=83886080
-o cleanup_service_name=bigcleanup
bigcleanup unix n - y - 0 cleanup
-o message_size_limit=83886080Если у вас не «голый» Postfix, а готовая сборка, правки в main.cf могут не пережить обновление. В mailcow-dockerized по документации проекта message_size_limit задаётся в data/conf/postfix/extra.cf, а следом правятся max_message в data/conf/rspamd/local.d/options.inc, max_size для clamav и oletools в antivirus.conf и external_services.conf, MaxScanSize/MaxFileSize в data/conf/clamav/clamd.conf; затем docker compose restart postfix-mailcow rspamd-mailcow clamd-mailcow. Так апдейт ничего не затрёт, а крупные письма не проскочат мимо проверок. В iRedMail и в панельных сборках смотрите их собственные шаблоны и include-файлы. Универсальное правило: после любого обновления сборки прогоняйте postconf -n | grep size_limit и сверяйтесь с тем, что вы задумывали.
Проверять результат нужно письмом, а не глазами по конфигу. Я генерирую файл нужного размера и отправляю через swaks — так виден и код ответа, и то, на каком этапе он пришёл:
# файл на 30 МБ
head -c 31457280 /dev/urandom > /tmp/test30.bin
swaks --to user@example.com --from test@example.com \
--server mail.example.com --attach @/tmp/test30.bin \
--header 'Subject: size test 30M'Если ответ 250 Ok — лимит пропускает. Если 552 5.3.4 — смотрим, на MAIL FROM он пришёл или после DATA. Если 452 4.3.1 — идём смотреть df -h /var/spool/postfix, дело не в лимите.
- postconf -e вместо ручной правки main.cf, затем postconf -n на предмет unused parameter
- postfix reload вместо restart — не рвёт активные сессии
- postconf -n и postconf -M — проверить, что применилось и не переопределено
- master.cf: отдельный cleanup для сервиса с увеличенным лимитом
- mailcow: extra.cf + Rspamd max_message + ClamAV MaxScanSize, а не правка main.cf внутри контейнера
Приоритеты: что делать сегодня, а на что можно забить
Если разбираете конкретную жалобу «письмо не уходит», порядок такой. Сначала лог — три грепа из второго раздела дают ответ за минуту и сразу отсекают половину гипотез: ваш это лимит или чужой. Потом арифметика: размер файла × 1,4 против текущего postconf message_size_limit. Потом свободное место на разделе очереди. И только потом правки конфига. Я видел, как люди сутки крутили Dovecot и квоты, а в логе всё это время лежало честное 552 5.3.4 от MX получателя — то есть лимит был вообще не их.
Что я считаю обязательным на любом почтовом сервере, который обслуживаю: осмысленный message_size_limit (не дефолтные 10 МБ, если люди реально шлют сканы, но и не «безлимит»), согласованные с ним лимиты почтовых файлов, явный queue_minfree и алерт на свободное место в /var/spool/postfix. Это полчаса работы один раз и минус целый класс заявок. Отдельным пунктом — рассказать пользователям реальный потолок вложения в мегабайтах: не «лимит 50», а «файл до 35 МБ пройдёт, больше — ссылкой».
Чем можно спокойно пренебречь. Не нужно вычислять коэффициент раздувания с точностью до процента — 1,4 с запасом закрывает и quoted-printable, и подписи, и цепочки заголовков. Не нужно городить разные лимиты для десятка доменов, если бизнес-потребность одна. Не нужно паниковать из-за предупреждения queue_minfree should be at least 1.5*message_size_limit при старте — это именно предупреждение, почта работает, но исправить стоит в ближайшее окно.
И спорный момент, где я скажу прямо: единого «правильного» значения лимита не существует, это торговля между удобством пользователей и здоровьем сервера. Мой выбор для офиса до 50 рабочих мест — 50 МБ на письмо плюс нормальное файловое хранилище для всего, что больше. Кто-то оставляет заводские 10 МБ и жёстко гонит всех в облако — тоже честная позиция, если пользователям объяснили правила. Чего делать точно не стоит — ставить 200 МБ «чтобы отстали» на разделе очереди в 10 гигабайт: это не решение проблемы, а её перенос на момент, когда упадёт вся почта.
- Сегодня: греп логов → арифметика ×1,4 → df по разделу очереди
- На этой неделе: согласовать message_size_limit с mailbox/virtual limits, задать queue_minfree
- В мониторинг: свободное место на /var/spool/postfix и появление 452 4.3.1 в логе
- Пользователям: назвать реальный потолок вложения в мегабайтах и альтернативу для больших файлов
Частые вопросы
Файл 20 МБ, лимит 25 МБ — почему письмо не проходит?
Потому что вложение едет закодированным в Base64: +33 % по RFC 2045 плюс переносы строк каждые 76 символов с CRLF, итого коэффициент около 1,37. Файл 20 МиБ превращается примерно в 28,7 млн байт на проводе, к этому добавляются заголовки, MIME-границы и подпись. Против лимита 26 214 400 байт это не проходит. Считайте так: максимальный файл = message_size_limit / 1,4.
Какое значение message_size_limit ставить?
От реальной потребности: размер самого большого нужного файла × 1,4 + 2 МБ. Для сканов на 25 МБ — 41943040 (40 МБ) или 52428800 (50 МБ). Значение 0 (без лимита) на боевом сервере не используйте: один сбойный клиент забьёт раздел очереди, и Postfix начнёт отбивать всю почту с 452 4.3.1.
Поднял message_size_limit — почта перестала доставляться в ящики. Что случилось?
Скорее всего, вы не подняли mailbox_size_limit (для local) или virtual_mailbox_limit (для virtual) — оба по умолчанию 51200000. Если лимит почтового файла меньше лимита сообщения, агент доставки завершается с fatal и не работает вообще, письма копятся в очереди. Смотрите в mail.log строку «configuration error: ... is smaller than message_size_limit». Лечится установкой этих параметров в 0 (если квоты считает Dovecot) или в значение не меньше message_size_limit.
Что означает ошибка 452 4.3.1 Insufficient system storage?
Не хватает свободного места в файловой системе очереди. Начиная с Postfix 2.1 сервер отвергает MAIL FROM, если свободно меньше 1,5 × message_size_limit — коэффициент зашит в коде. Отбивается вся входящая почта, а не только крупные письма. Проверьте `df -h /var/spool/postfix`, освободите место и задайте queue_minfree явно, минимум в 1,5 раза больше лимита сообщения.
Как узнать, чей лимит сработал — мой или получателя?
По логу и по тексту bounce. Если 552 5.3.4 сгенерировал ваш smtpd, в mail.log будет ваша строка reject с вашим IP клиента. Если отказ пришёл в ответ от чужого MX, в логе он будет в строке «said: 552 ...» с именем удалённого сервера. Потолок чужой стороны видно заранее: `swaks --server mx.partner.example --quit-after=EHLO | grep -i size` покажет объявленное значение SIZE по RFC 1870.
Нужно ли разрешать вложения по 100 МБ и больше?
Практического смысла мало. По официальным справкам Яндекс принимает на свои ящики письма до 30 МБ, Gmail и VK Почта ограничивают вложения 25 МБ, и ваше гигантское письмо всё равно отобьётся у получателя — только уже отложенным bounce-ом, который пользователь заметит не сразу. Крупные файлы правильнее отдавать ссылкой на файловое хранилище, а лимит письма держать в пределах 40–50 МБ.
Postfix лимит подняли, а в веб-почте вложение всё равно не прикрепляется. Почему?
Потому что у веб-почты свои ограничения, до Postfix дело не доходит. Проверьте `client_max_body_size` у nginx (по умолчанию 1 МБ, ошибка 413 Request Entity Too Large), `upload_max_filesize` и `post_max_size` в php.ini (по умолчанию 2 и 8 МБ) и `max_message_size` в конфиге Roundcube. Порог в веб-почте считайте с поправкой на Base64: примерно message_size_limit / 1,4.
Источники
- Postfix Configuration Parameters (postconf.5) — Параметры message_size_limit (default 10240000), mailbox_size_limit (default 51200000, «This limit must not be smaller than the message size limit»), virtual_mailbox_limit (default 51200000), queue_minfree (default 0, «rejects MAIL FROM commands when the amount of free space is less than 1.5*$message_size_limit, Postfix version 2.1 and later»), smtpd_proxy_options. https://www.postfix.org/postconf.5.html
- RFC 2045: MIME Part One, раздел 6.8 Base64 Content-Transfer-Encoding — «The encoded data are consistently only about 33 percent larger than the unencoded data» и требование «lines of no more than 76 characters each». https://www.rfc-editor.org/rfc/rfc2045.html
- Исходный код Postfix: src/smtpd/smtpd_check.c — Функции smtpd_check_size() (552 5.3.4 «Message size exceeds fixed limit») и smtpd_check_queue() (452 4.3.1 «Insufficient system storage», warning «not enough free space in mail queue»), переменная smtpd_space_multf = 1.5; в smtpd.c — warning «queue file size limit exceeded», проверка queue_minfree и комментарий о 2.5*message_size_limit при speed_adjust. https://github.com/vdukhovni/postfix/blob/master/postfix/src/smtpd/smtpd_check.c и https://github.com/vdukhovni/postfix/blob/master/postfix/src/smtpd/smtpd.c
- Исходный код Postfix: src/local/local.c и src/virtual/virtual.c — msg_fatal «configuration error: mailbox_size_limit is smaller than message_size_limit» (local.c) и «configuration error: virtual_mailbox_limit is smaller than message_size_limit» (virtual.c) — агент доставки не стартует при конфликте лимитов. https://github.com/vdukhovni/postfix/blob/master/postfix/src/local/local.c , https://github.com/vdukhovni/postfix/blob/master/postfix/src/virtual/virtual.c
- RFC 1870: SMTP Service Extension for Message Size Declaration — Ключевое слово SIZE в ответе на EHLO и параметр SIZE= в команде MAIL FROM, по которому Postfix отклоняет письмо до передачи тела. https://www.rfc-editor.org/rfc/rfc1870.html
- Postfix Announcements — Postfix 3.11.0 — стабильный релиз от 5 марта 2026, актуальный патч-уровень ветки на сентябрь 2026 — 3.11.7; значения по умолчанию лимитов размера не менялись. https://www.postfix.org/announcements.html
- Dovecot: quota plugin (2.3 и 2.4) — quota_max_mail_size (v2.2.29+, default 0) — https://doc.dovecot.org/2.3/settings/plugin/quota-plugin/ ; quota_mail_size, SIZE для LMTP и APPENDLIMIT для IMAP — https://doc.dovecot.org/main/core/plugins/quota.html
- Rspamd: Common options — max_message — maximum size of the message to be scanned (50Mb by default). https://docs.rspamd.com/configuration/options/
- mailcow: dockerized documentation — Max. message size (attachment size) — extra.cf, rspamd options.inc max_message, antivirus.conf/external_services.conf max_size, clamd.conf MaxScanSize/MaxFileSize, docker compose restart. https://docs.mailcow.email/manual-guides/Postfix/u_e-postfix-attachment_size/
- Справка Яндекс Почты: «Слишком большой размер вложения» — «Максимальный размер писем с вложениями, отправляемыми на почтовый ящик на Яндексе, не должен превышать 30 МБ». https://yandex.ru/support/yandex-360/customers/mail/ru/bounces/yandex/message-size-exceeds-fixed-limit
- Справка Gmail: вложения — Для личных аккаунтов Gmail лимит вложений 25 МБ, крупнее — ссылка Google Диска. https://support.google.com/mail/answer/6584
- Помощь VK Почты (Mail.ru): отправить или скачать файл — «Максимальный размер файла — 25 МБ», файл большего размера загружается в облако и прикрепляется ссылкой. https://help.mail.ru/vkmail/letters/file/
- Roundcube: config/defaults.inc.php — $config['max_message_size'] = '100M'; «Note that SMTP server(s) may use a different value». https://github.com/roundcube/roundcubemail/blob/master/config/defaults.inc.php
