Revisando los correos electrónicos: salida de la tarea rake de prueba

Revisé recientemente los correos electrónicos: tarea y el código relacionado con el objetivo de probar cada una de las rutas de error y retocar el texto de error.

También descubrí que los efectos de establecer DISCOURSE_SMTP_ENABLE_STARTTLS=false son (en su mayoría) nulos. Establecer esto en realidad no deshabilitó STARTTLS y, de hecho, puede coexistir perfectamente con TLS en el momento de la conexión (DISCOURSE_SMTP_FORCE_TLS=true).

Así que he:

Sin embargo, antes de fusionar esto, creo que una advertencia para administradores en el panel cuando se establece DISCOURSE_SMTP_ENABLE_STARTTLS=false es adecuada. Me imagino que al menos un autoalojador lo ha configurado pero no lo necesita y en realidad depende de STARTTLS.

4 Me gusta

¡Eso suena a un buen trabajo! Una cosa que (creo que) he notado es que la tarea de rake en realidad no usa el mismo código que el envío real (como desde la página de prueba de correo electrónico de /admin/). Estoy bastante seguro de que he tenido un caso en el que funcionó en la UX pero no en la tarea de rake (¿o tal vez fue al revés?)

Mientras lo tienes fresco en mente, si pudieras asegurarte de que cuando realmente envía, lo hace utilizando el mismo código que usa Discourse, sería genial.

2 Me gusta

También estamos trabajando en eso, y en mejorar el registro cuando falla un trabajo de correo electrónico en cola. :+1:

4 Me gusta

¿Hay algo que deba hacer en el foro que alojas?

4 Me gusta

No, esta alerta no debería aparecer en nuestro hosting. Lo solucionaremos, gracias por el informe como siempre.

5 Me gusta

@supermathie, ¿vale la pena enviar un mensaje privado a todos los administradores de cada sitio que tenga esta variable configurada? Nuestro sistema actual de verificación de problemas lo hará, y no estoy seguro de que sea necesario aquí, dado que en la mayoría de los casos, esto tiene un efecto nil. Idealmente, querría mostrar esto solo en el panel de control sin notificar a los usuarios administradores, no estoy seguro de que nuestra estructura actual de verificación de problemas admita ese caso de uso.

Creo que sí: me parece extremadamente probable que, dada la confusión de muchos administradores con la configuración del correo electrónico, alguien tenga esta variable configurada cuando en realidad depende de starttls.

Probablemente nadie debería tenerla configurada.

Prefiero tener una advertencia espuria que romper silenciosamente la configuración de correo electrónico de alguien.

La alternativa es eliminar la verificación y neutralizar la variable para que no haga nada en absoluto.

1 me gusta

Sería bueno que la advertencia no apareciera cuando el servidor SMTP saliente es localhost (es decir, coincide con el nombre de dominio de Discourse), ya que no se necesita TLS entre el contenedor Docker y el host, al ser la misma máquina.

1 me gusta

En este caso puedes eliminar la variable del entorno.

Solo usará STARTTLS si se ofrece.

1 me gusta

Tuve el caso en la versión actual de que la línea comentada (el valor predeterminado es true) junto con force_tls impedía el envío de correos electrónicos. Así que la he descomentado y la he puesto en false. El envío de correos electrónicos ahora funciona, pero tengo este mensaje en el backend…

Depende un poco de en qué puerto se ejecute su proveedor de correo… no funcionan ambas cosas y definitivamente tienen un impacto.

También noté esto. Después de actualizar Discourse el 28 de noviembre, comencé a ver fallos en la entrega de correo con el mensaje de error 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'

Al igual que Johann Christoph, anteriormente tenía DISCOURSE_SMTP_ENABLE_START_TLS comentado y DISCOURSE_SMTP_FORCE_TLS establecido en true para TLS implícito y funcionaba de maravilla. Pero ahora tengo que establecer explícitamente DISCOURSE_SMTP_ENABLE_START_TLS en false para que la entrega de correo funcione, lo que por supuesto activa el mensaje mencionado en el panel de administración.

1 me gusta

Será force_tls lo que impide el envío de correos electrónicos: esto fuerza TLS en el momento de la conexión y probablemente solo sea adecuado para el puerto 465.

¡Un unicornio!

¿Qué parámetros SMTP está utilizando (menos nombre de usuario/contraseña)?

Puerto 465 con ENABLE_START_TLS=false, FORCE_TLS=true y OPEN_TIMEOUT=10. Este último se debe a extraños errores de tiempo de espera que comencé a ver después de una actualización del sistema hace unos tres años, pero me cortaré la gorra si eso está relacionado con el problema descrito anteriormente.

Mientras tanto, eché un vistazo al historial de confirmaciones y noté que el gem mail se actualizó a la versión 2.9.0 solo tres días antes de la actualización que introdujo el problema de mi lado (#36254). Hay una entrada en las notas de la versión de eso que dice “SMTP: refactor and accept starttls :always and :auto by @eval in #1536”. No sé mucho sobre Ruby, pero este cambio en el PR referenciado me parece un poco sospechoso:

Dado que DISCOURSE_SMTP_ENABLE_START_TLS está documentado como verdadero por defecto (es decir, si está comentado), ¿es posible que esta sea la raíz del problema?

Como escribí, he configurado force_TLS:

DISCOURSE_SMTP_FORCE_TLS = true

y ENABLE_START_TLS explícitamente en false… entonces el envío de correo funciona, siempre que el servidor de correo se ejecute en 465.

Para los servidores de correo que se ejecutan en 567, debe ser exactamente al revés.

Desde entonces, tengo una advertencia en el panel de control en el backend… pero el envío de correo funciona sin problemas.

Para poder establecer DISCOURSE_SMTP_ENABLE_START_TLS en false, es necesario comentarlo, ya que de lo contrario está configurado en true por defecto. Precisamente eso fue lo que me causó el problema. Sin embargo, esto solo ocurrió con la última compilación (2025.12.0-latest).

Vaya, este fue un mal cambio.

enable_starttls REQUERIRÁ el uso de starttls, pero enable_starttls_auto es oportunista: solo negociará tls si se ofrece.

Y si el servidor de correo fue conectado a través de TLS inicial, no ofrecerá starttls:

○ → openssl s_client -connect localhost:5587 -starttls smtp
250 CHUNKING
EHLO localhost
250-testmailrelay
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-AUTH PLAIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250 CHUNKING

¿Por qué demonios habrían hecho eso? :facepalm:
La dificultad aquí es que nunca deberíamos haber ofrecido esta configuración en primer lugar, debería haber sido algo como:

DISCOURSE_SMTP_TLS_MODE = starttls_auto # [ none | starttls | starttls_auto (default) | tls ]

En aras de intentar que la gente haga menos configuración, no más, creo que este enfoque es el mejor:

1 me gusta

Esto ahora está fusionado, ya no es necesario deshabilitar explícitamente STARTTLS, Discourse se encargará de eso si TLS está habilitado.

Sí, funciona correctamente de nuevo. ¡Gracias!