Hasta hace bien poco, habíamos tenido una dulce relación con DataBase Mail, la solución empresarial de Microsoft SQL Server que permite enviar correos electrónicos desde el propio motor de base de datos. Decimos lo de “una dulce relación” porque, después de configurar los perfiles y cuentas de forma correcta, no habíamos tenido ningún tipo de problema y esto, como suele ocurrir, había provocado que no le prestáramos demasiada atención durante años.

Como resultado de una actualización del servidor de correo, que dejó el servidor inaccesible durante 20 minutos, dejamos de recibir correos de una de nuestras instancias de BD. Sólo de una de ellas, lo que nos hizo pensar que el problema podría no estar en el servidor de correo.

Enseguida nos pusimos manos a la obra, revisando el log del DataBase Mail y nos sorprendió bastante que después de los 20 minutos de la caída de servicio, no hubiera ni rastro de registros en el log del DataBaseMail...

Antes de continuar, me gustaría hacer un breve comentario sobre la arquitectura del correo electrónico de base de datos, que está basada en colas y usa tecnologías de Service Broker.

La base de datos del sistema msdb contiene los objetos de mensajería que DataBase Mail utiliza para enviar los correos electrónicos que se generan con sp_send_dbmail. Esto significa  que, cuando desde un procedimiento almacenado hacemos uso de sp_send_dbmail para enviar un correo, toda la información relativa al mismo se almacena en tablas, dentro de la BD msdb, como sysmail_allitems.

Por otro lado, existe un ejecutable, invocado por el Service Broker, que se encarga de leer de una cola de correos en la BD msdb y de enviar mensajes al servidor de correo electrónico a través del protocolo SMTP.

Este diagrama, que podéis encontrar en la documentación de Microsoft, ilustra su arquitectura:

Comprobamos lo que nos estaba ocurriendo poniendo una traza de SQL Server Profiler sobre una llamada, que invocamos de forma manual, a sp_send_dbmail:

EXEC msdb.dbo.sp_send_dbmail
	@profile_name = 'NombrePerfil',
	@recipients = 'recipient@mail.com',
	@body = 'Probandooooooooooooo',
	@subject = 'A ver si funsiona';

Constatamos que, al enviar el mensaje, toda la información de msdb se almacenaba correctamente, pero que nuestro mensaje de prueba, al igual que ocurría con otros mensajes que se estaban generando, se acumulaba en la cola de elementos no enviados.

Ejecutando sysmail_help_status_sp pudimos ver  que el estado de la cola de correo era inactivo, así que decidimos detenerla, haciendo uso de la sentencia sysmail_stop_sp y reanudándola posteriormente con sysmail_start_sp.

Esto no surtió ningún tipo de efecto, los mensajes se seguían acumulando y nuestra frustración creciendo. ¡Ojo! estad atentos al crecimiento del log de msdb, porque es probable que tengáis que darle algo de espacio.

En los informes del Service Broker vimos que el problema se encontraba en la cola del proceso externo y lo confirmamos al comparar las trazas de Profiler de la instancia que no tenía problemas frente a la que sí que los tenía. En ellas observamos que en la instancia problemática no se estaba invocando el proceso sp_ExternalQueueListener.

¿Y cuál fue la solución? tristemente, reiniciar la instancia de SQL Server fue la única manera de conseguir reanudar el envío de correos. Realmente, hicimos un failover a la instancia que teníamos como pasiva hasta ese momento, pero a efectos prácticos, es lo mismo. Una vez hecho el failover, se enviaron todos los correos electrónicos que habían sido encolados.