Revisei recentemente os emails:task e o código relacionado com o objetivo de testar todos os caminhos de falha e retocar o texto de erro.
Também descobri que os efeitos de definir DISCOURSE_SMTP_ENABLE_STARTTLS=false são (na maioria) nulos. Definir isso não desativou realmente o STARTTLS e, de fato, ele pode coexistir perfeitamente com TLS no momento da conexão (DISCOURSE_SMTP_FORCE_TLS=true).
Antes de mesclar isso, acho que um aviso de administrador no painel para quando DISCOURSE_SMTP_ENABLE_STARTTLS=false for definido é adequado. Imagino que haja pelo menos um auto-hospedeiro que definiu isso, mas não precisa e está realmente confiando no STARTTLS.
Isso parece um bom trabalho! Uma coisa que eu (acho que) notei é que a tarefa rake não usa o mesmo código que o envio real (como da página de teste de e-mail /admin/email). Tenho quase certeza de que tive um caso em que funcionou no UX, mas não na tarefa rake (ou talvez tenha sido o contrário?)
Enquanto isso está fresco em sua mente, se você pudesse ver que, pelo menos quando realmente envia, o faz usando o mesmo código que o Discourse, seria ótimo.
@supermathie vale a pena enviar uma mensagem privada para todos os administradores em todos os sites que têm essa variável definida? Nosso sistema atual de verificação de problemas fará isso, e não tenho certeza se é garantido aqui, dado que, na maioria das vezes, isso tem um efeito nil. Idealmente, eu gostaria de mostrar isso apenas no painel sem notificar os usuários administradores, não tenho certeza se nossa estrutura atual de verificação de problemas suporta esse caso de uso.
Eu acho que sim - acho extremamente provável que, dada a confusão de muitos administradores com a configuração de e-mail, alguém tenha essa variável definida quando na verdade depende do starttls.
Ninguém deveria tê-la definida, provavelmente.
Prefiro ter um aviso espúrio do que quebrar silenciosamente a configuração de e-mail de alguém.
A alternativa é remover a verificação e neutralizar a variável para que ela não faça nada.
Seria bom se o aviso não aparecesse quando o servidor SMTP de saída for localhost (ou seja, corresponder ao nome de domínio do Discourse), pois o TLS entre o contêiner Docker e o host não é necessário, já que eles estão na mesma máquina.
Eu tive o caso na versão atual em que a linha comentada (o padrão é true) juntamente com force_tls bloqueava o envio de e-mail. Eu a comentei e a defini como false. O envio de e-mail agora funciona, mas recebo esta mensagem no backend…
Depende um pouco da porta em que seu provedor de e-mail está rodando… ambas as configurações não funcionam e definitivamente têm impacto.
Notei isso também. Após atualizar o Discourse em 28 de novembro, comecei a ver falhas na entrega de e-mails com a mensagem de erro Job exception: :enable_starttls and :tls are mutually exclusive. Set :tls if you're on an SMTPS connection. Set :enable_starttls if you're on an SMTP connection and using STARTTLS for secure TLS upgrade.
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'
Assim como Johann Christoph, eu anteriormente tinha DISCOURSE_SMTP_ENABLE_START_TLS comentado e DISCOURSE_SMTP_FORCE_TLS definido como true para TLS implícito e funcionava perfeitamente. Mas agora preciso definir explicitamente DISCOURSE_SMTP_ENABLE_START_TLS como false para que a entrega de e-mail funcione, o que, é claro, aciona a mensagem mencionada no painel de administração.
Porta 465 com ENABLE_START_TLS=false, FORCE_TLS=true e OPEN_TIMEOUT=10. Este último é devido a estranhos erros de tempo limite que comecei a ver após uma atualização do sistema há cerca de três anos, mas eu comeria meu chapéu se isso estivesse relacionado ao problema descrito acima.
Enquanto isso, dei uma olhada no histórico de commits e notei que a gem mail foi atualizada para a versão 2.9.0 apenas três dias antes da atualização que introduziu o problema do meu lado (#36254). Há uma entrada nas notas de lançamento disso que diz “SMTP: refactor and accept starttls :always and :auto by @eval in #1536”. Eu não sei muito sobre Ruby, mas essa mudança no PR referenciado parece meio suspeita para mim:
Dado que DISCOURSE_SMTP_ENABLE_START_TLS é documentado como sendo true por padrão (ou seja, se comentado), é possível que esta seja a raiz do problema?
Para poder definir DISCOURSE_SMTP_ENABLE_START_TLS como false, você precisa descomentá-lo — pois, caso contrário, ele estará definido como true por padrão. Foi exatamente isso que causou o meu problema. No entanto, isso só ocorreu com a compilação mais recente (2025.12.0-latest).
Por que diabos eles fariam isso?
A dificuldade aqui é que nunca deveríamos ter oferecido essa configuração em primeiro lugar, deveria ter sido algo como: