Недавно я проанализировал код, связанный с emails:task, с целью протестировать каждый сценарий обработки ошибок и уточнить текст сообщений об ошибках.
Также я обнаружил, что установка DISCOURSE_SMTP_ENABLE_START_TLS=false (почти) не оказывает никакого эффекта. Эта настройка не отключает STARTTLS, и, более того, она может спокойно сосуществовать с TLS при установлении соединения (DISCOURSE_SMTP_FORCE_TLS=true).
Однако перед слиянием я считаю необходимым добавить предупреждение для администратора в панели управления при установке DISCOURSE_SMTP_ENABLE_START_TLS=false. Представляю, что есть хотя бы один администратор, самостоятельно размещающий Discourse, который установил эту опцию, но не нуждается в ней и на самом деле полагается на STARTTLS.
Звучит как хорошая работа! Одна вещь, которую я (кажется, заметил): задача rake на самом деле не использует тот же код, что и фактическая отправка (например, со страницы тестирования /admin/email). Я почти уверен, что у меня был случай, когда это работало в UX, но не в задаче rake (или, может быть, наоборот?).
Пока это свежо в памяти, если бы вы могли убедиться, что при реальной отправке используется тот же код, что и в Discourse, это было бы здорово.
@supermathie, стоит ли отправлять личное сообщение каждому администратору на каждом сайте, где установлена эта переменная? Наша текущая система проверок проблем делает это, но я не уверен, что это оправдано в данном случае, поскольку в большинстве случаев это не имеет никакого эффекта (nil). В идеале я хотел бы показывать это только в панели управления, не уведомляя администраторов, но не уверен, что текущая структура проверок проблем поддерживает такой сценарий использования.
Я так думаю — учитывая, насколько многие администраторы запутались в настройке почты, крайне вероятно, что кто-то установил эту переменную, хотя на самом деле полагается на STARTTLS.
Вероятно, никто не должен её устанавливать.
Лучше получить ложное предупреждение, чем молча сломать чью-то настройку почты.
Альтернатива — убрать проверку и полностью обесценить переменную, чтобы она ничего не делала.
Было бы неплохо, если бы предупреждение не появлялось, когда исходящий SMTP-сервер — это localhost (то есть совпадает с доменным именем Discourse), так как TLS между Docker-контейнером и хостом не требуется, поскольку это одна и та же машина.
В текущей версии я столкнулся со случаем, когда закомментированная строка (по умолчанию true) вместе с параметром force_tls блокировала отправку электронной почты. Я раскомментировал её и установил значение false. Отправка писем теперь работает, но в админ-панели появляется это сообщение…
Это немного зависит от того, на каком порту работает ваш почтовый провайдер… оба варианта не работают и определённо влияют на процесс.
Я тоже это заметил. После обновления Discourse 28 ноября я начал сталкиваться с ошибками доставки почты с сообщением: Job exception: :enable_starttls и :tls взаимоисключающие. Установите :tls, если используете соединение SMTPS. Установите :enable_starttls, если используете соединение SMTP и применяете STARTTLS для безопасного обновления до TLS.
Стек вызовов (Backtrace)
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/mail-2.9.0/lib/mail/network/delivery_methods/smtp.rb:159:in `build_smtp_session'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/mail-2.9.0/lib/mail/network/delivery_methods/smtp.rb:154:in `start_smtp_session'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/mail-2.9.0/lib/mail/network/delivery_methods/smtp.rb:108:in `deliver!'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/mail-2.9.0/lib/mail/message.rb:269:in `deliver!'
/usr/local/lib/ruby/3.3.0/delegate.rb:87:in `method_missing'
/var/www/discourse/lib/email/sender.rb:296:in `send'
/var/www/discourse/app/jobs/regular/user_email.rb:80:in `send_user_email'
/var/www/discourse/app/jobs/regular/user_email.rb:40:in `execute'
/var/www/discourse/app/jobs/base.rb:318:in `block (2 levels) in perform'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rails_multisite-7.0.0/lib/rails_multisite/connection_management/null_instance.rb:49:in `with_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rails_multisite-7.0.0/lib/rails_multisite/connection_management.rb:17:in `with_connection'
/var/www/discourse/app/jobs/base.rb:305:in `block in perform'
/var/www/discourse/app/jobs/base.rb:301:in `each'
/var/www/discourse/app/jobs/base.rb:301:in `perform'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:220:in `execute_job'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:185:in `block (4 levels) in process'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:180:in `traverse'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:183:in `block in traverse'
/var/www/discourse/lib/sidekiq/suppress_user_email_errors.rb:6:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:182:in `traverse'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:183:in `block in traverse'
/var/www/discourse/lib/sidekiq/discourse_event.rb:6:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:182:in `traverse'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:183:in `block in traverse'
/var/www/discourse/lib/sidekiq/pausable.rb:131:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:182:in `traverse'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:183:in `block in traverse'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/job/interrupt_handler.rb:9:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:182:in `traverse'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:183:in `block in traverse'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/metrics/tracking.rb:26:in `track'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/metrics/tracking.rb:134:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:182:in `traverse'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:173:in `invoke'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:184:in `block (3 levels) in process'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:145:in `block (6 levels) in dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/job_retry.rb:118:in `local'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:144:in `block (5 levels) in dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/config.rb:39:in `block in <class:Config>'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:139:in `block (4 levels) in dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:281:in `stats'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:134:in `block (3 levels) in dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/job_logger.rb:15:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:133:in `block (2 levels) in dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/job_retry.rb:85:in `global'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:132:in `block in dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/job_logger.rb:40:in `prepare'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:131:in `dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:183:in `block (2 levels) in process'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:182:in `handle_interrupt'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:182:in `block in process'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:181:in `handle_interrupt'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:181:in `process'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:86:in `process_one'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:76:in `run'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/component.rb:10:in `watchdog'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/component.rb:19:in `block in safe_thread'
Как и Йоханн Кристоф, ранее у меня было закомментировано DISCOURSE_SMTP_ENABLE_START_TLS, а DISCOURSE_SMTP_FORCE_TLS установлен в true для неявного TLS, и всё работало как по маслу. Но теперь для корректной доставки писем мне приходится явно устанавливать DISCOURSE_SMTP_ENABLE_START_TLS в false, что, разумеется, вызывает упомянутое выше сообщение в панели администратора.
Скорее всего, проблема в том, что force_tls блокирует отправку писем — это принудительное использование TLS при установлении соединения, и, вероятно, подходит только для порта 465.
Уникально!
Какие параметры SMTP вы используете (без имени пользователя и пароля)?
Порт 465 с параметрами ENABLE_START_TLS=false, FORCE_TLS=true и OPEN_TIMEOUT=10. Последний параметр был добавлен из-за странных ошибок тайм-аута, которые я начал замечать после обновления системы примерно три года назад, но я готов съесть свою шляпу, если это как-то связано с проблемой, описанной выше.
Тем временем я изучил историю коммитов и заметил, что gem mail был обновлён до версии 2.9.0 всего за три дня до обновления, которое вызвало проблему на моей стороне (#36254). В примечаниях к выпуску указано: «SMTP: рефакторинг и поддержка starttls :always и :auto от @eval в #1536». Я не очень хорошо знаю Ruby, но это изменение в указанном PR выглядит подозрительно:
Учитывая, что параметр DISCOURSE_SMTP_ENABLE_START_TLS по умолчанию установлен в true (то есть если он закомментирован), возможно, именно это является корнем проблемы?
Чтобы установить DISCOURSE_SMTP_ENABLE_START_TLS в false, необходимо закомментировать его, так как по умолчанию он равен true. Именно это и вызвало у меня проблему. Однако это проявилось только в последней сборке (2025.12.0-latest).
enable_starttls ТРЕБУЕТ использования starttls, тогда как enable_starttls_auto работает в режиме «по возможности» — он будет согласовывать TLS только если сервер его предлагает.
А если подключение к почтовому серверу уже установлено через TLS с самого начала, он не предложит starttls:
Отлично, меня просто раздражало предупреждение о том, что отключение STARTTLS не требуется, хотя наш SMTP-сервер вообще не поддерживает STARTTLS (только явный TLS). Теперь, при установке DISCOURSE_SMTP_FORCE_TLS=true, STARTTLS отключается неявно?