Autor: Francisco

  • Configurar Database Mail en SQL Server: perfiles, cuentas y sp_send_dbmail

    Database Mail es el mecanismo nativo de SQL Server para enviar correos electrónicos directamente desde la base de datos — usado típicamente para alertas de Agent Jobs, notificaciones de errores, o reportes automáticos. Esta guía cubre cómo crear un perfil nuevo replicando la configuración de uno existente, junto con la prueba de envío y el rollback completo si algo sale mal.

    Add Post

    Conceptos: perfil, cuenta y su relación

    Database Mail separa la configuración en tres piezas independientes, relacionadas entre sí:

    • Cuenta (account) — contiene los datos técnicos de conexión SMTP: servidor, puerto, credenciales, si usa SSL, y el correo/nombre que aparece como remitente.
    • Perfil (profile) — una capa de abstracción por encima de una o varias cuentas. Es el nombre que efectivamente se usa al enviar un correo (por ejemplo, desde un Job de SQL Server Agent) — nunca se referencia la cuenta directamente.
    • Relación perfil-cuenta — vincula ambos, con un sequence_number que define el orden de intento: si la cuenta principal falla, Database Mail prueba la siguiente cuenta asociada al mismo perfil, en orden.

    Esta separación permite, por ejemplo, tener un mismo perfil con dos cuentas SMTP distintas como respaldo, sin que las aplicaciones o jobs que usan el perfil necesiten saber nada sobre el failover.

    Script de creación completo

    USE msdb;
    GO
    
    -- 1. Crear la cuenta SMTP
    EXEC msdb.dbo.sysmail_add_account_sp
        @account_name              = 'cuenta_nuevo_entorno',
        @description               = 'Cuenta SMTP para el nuevo entorno',
        @email_address             = '[email protected]',
        @display_name              = 'Alertas Sistema',
        @replyto_address           = NULL,
        @mailserver_name           = 'smtp.tudominio.com',
        @port                      = 25,
        @enable_ssl                = 0,
        @username                  = NULL,
        @password                  = NULL,
        @use_default_credentials   = 0;
    GO
    
    -- 2. Crear el perfil
    EXEC msdb.dbo.sysmail_add_profile_sp
        @profile_name = 'PERFIL_NUEVO_ENTORNO',
        @description  = 'Perfil de correo para el nuevo entorno';
    GO
    
    -- 3. Vincular la cuenta al perfil
    EXEC msdb.dbo.sysmail_add_profileaccount_sp
        @profile_name    = 'PERFIL_NUEVO_ENTORNO',
        @account_name    = 'cuenta_nuevo_entorno',
        @sequence_number = 1;
    GO
    
    -- 4. Autorizar el perfil para uso público (todos los usuarios de msdb)
    EXEC msdb.dbo.sysmail_add_principalprofile_sp
        @profile_name   = 'PERFIL_NUEVO_ENTORNO',
        @principal_name = 'public',
        @is_default     = 0;
    GO

    Qué hace cada procedimiento almacenado

    ProcedimientoFunción
    sysmail_add_account_spCrea la cuenta SMTP con los parámetros de conexión
    sysmail_add_profile_spCrea el perfil (el nombre lógico que se usará al enviar correos)
    sysmail_add_profileaccount_spVincula una cuenta existente a un perfil existente
    sysmail_add_principalprofile_spOtorga permiso de uso del perfil a un principal (usuario o rol de base de datos); public lo hace disponible para todos

    Sobre @is_default: cuando se marca en 1, ese perfil se usa automáticamente si un envío de correo no especifica ningún @profile_name explícitamente. Es recomendable dejarlo en 0 salvo que se quiera intencionalmente ese comportamiento, para evitar que jobs mal configurados terminen enviando correos por el perfil equivocado.

    Validación de la configuración

    Antes de dar por buena la configuración, conviene confirmar que las tres piezas quedaron correctamente enlazadas consultando las vistas de catálogo correspondientes:

    -- Ver todos los perfiles configurados
    SELECT * FROM msdb.dbo.sysmail_profile;
    
    -- Ver todas las cuentas SMTP configuradas
    SELECT * FROM msdb.dbo.sysmail_account;
    
    -- Ver la relación entre perfiles y cuentas
    SELECT * FROM msdb.dbo.sysmail_profileaccount;
    
    -- Ver qué principals tienen acceso a cada perfil
    SELECT * FROM msdb.dbo.sysmail_principalprofile;

    Prueba de envío

    EXEC msdb.dbo.sp_send_dbmail
        @profile_name = 'PERFIL_NUEVO_ENTORNO',
        @recipients   = '[email protected]',
        @subject      = 'Prueba de perfil',
        @body         = 'El perfil está funcionando correctamente.';

    sp_send_dbmail encola el correo en la cola interna de Database Mail (tabla msdb.dbo.sysmail_mailitems) — el envío real no es instantáneo, lo procesa un proceso externo (DatabaseMail.exe) que SQL Server lanza bajo demanda. Para verificar si el correo realmente salió o quedó atascado:

    -- Ver el estado del último correo enviado
    SELECT TOP 10 * 
    FROM msdb.dbo.sysmail_allitems
    ORDER BY send_request_date DESC;
    
    -- Ver errores específicos de envío, si los hay
    SELECT * FROM msdb.dbo.sysmail_event_log
    ORDER BY log_date DESC;

    La columna sent_status en sysmail_allitems indica si el correo quedó como unsent, sent, o failed — este es el primer lugar a revisar si sp_send_dbmail se ejecutó sin error pero el correo nunca llegó.

    Rollback completo

    Si es necesario deshacer toda la configuración (por ejemplo, tras una prueba en un entorno que no corresponde), el orden de eliminación es el inverso al de creación — primero se deben quitar las relaciones antes que los objetos base:

    USE msdb;
    GO
    
    -- 1. Quitar el permiso del principal sobre el perfil
    EXEC msdb.dbo.sysmail_delete_principalprofile_sp
        @profile_name = 'PERFIL_NUEVO_ENTORNO',
        @principal_name = 'public';
    GO
    
    -- 2. Desvincular la cuenta del perfil
    EXEC msdb.dbo.sysmail_delete_profileaccount_sp
        @profile_name = 'PERFIL_NUEVO_ENTORNO',
        @account_name = 'cuenta_nuevo_entorno';
    GO
    
    -- 3. Eliminar el perfil
    EXEC msdb.dbo.sysmail_delete_profile_sp
        @profile_name = 'PERFIL_NUEVO_ENTORNO';
    GO
    
    -- 4. Eliminar la cuenta SMTP
    EXEC msdb.dbo.sysmail_delete_account_sp
        @account_name = 'cuenta_nuevo_entorno';
    GO

    Requisito adicional: habilitar Database Mail

    Si es la primera vez que se configura Database Mail en una instancia, el subsistema puede estar deshabilitado por defecto — hay que activarlo a nivel de configuración avanzada antes de que cualquiera de los procedimientos anteriores funcione:

    EXEC sp_configure 'show advanced options', 1;
    RECONFIGURE;
    GO
    
    EXEC sp_configure 'Database Mail XPs', 1;
    RECONFIGURE;
    GO

    Notas prácticas

    • El puerto 25 sin SSL (como en el ejemplo) es común en relays SMTP internos dentro de una red corporativa, pero no es apropiado para enviar directamente a través de internet — para eso se necesita normalmente el puerto 587 con @enable_ssl = 1 y credenciales de autenticación.
    • Si @use_default_credentials = 0 y no se especifica @username/@password, la cuenta SMTP asume que el servidor de correo permite retransmisión (relay) sin autenticación desde la IP del servidor SQL — esto debe estar explícitamente autorizado en el servidor de correo o relay correspondiente.
    • Antes de dar por completada la configuración en un entorno productivo, siempre correr la prueba de sp_send_dbmail y confirmar en sysmail_allitems que el estado sea sent, no solo confirmar que el EXEC no arrojó error.
  • Automatizando la conversión de video a 720p con find, ffprobe y HandBrake

    Script para reducir automáticamente la resolución de una biblioteca de video de 1080p (o superior) a 720p, aprovechando la aceleración por hardware de una GPU AMD para acelerar la codificación — útil para liberar espacio en disco en una biblioteca personal grande sin monopolizar la CPU durante horas.

    El script completo

    #!/bin/bash
    
    CARPETA_DESTINO="./Pelis_720p"
    
    # 1. Crear la carpeta de destino si no existe
    mkdir -p "$CARPETA_DESTINO"
    
    echo "=========================================================================="
    # 2. Buscar videos >= 1080p y procesarlos uno a uno
    find . -type f \( -name "*.mp4" -o -name "*.mkv" -o -name "*.avi" \) -exec sh -c '
        for f; do
            # Obtener el ancho del video de forma rápida
            w=$(ffprobe -v error -select_streams v:0 -show_entries stream=width -of default=nw=1:nk=1 "$f")
    
            # Filtrar solo si es igual o mayor a 1920px (1080p o superior)
            if [ "$w" -ge 1920 ] 2>/dev/null; then
                base=$(basename "$f" | sed "s/\.[^.]*$//")
                ext="${f##*.}"
                out="./Pelis_720p/${base}_converted.${ext}"
    
                # Si el archivo ya existe en el destino, saltarlo (protección anti-interrupciones)
                if [ -f "$out" ]; then
                    echo "Saltando (ya existe): $base"
                    continue
                fi
    
                echo "------------------------------------------------------------------"
                echo "Procesando: $f ($w px)"
                echo "------------------------------------------------------------------"
    
                # Ejecución optimizada con HandBrakeCLI + GPU AMD + baja prioridad de CPU
                nice -n 19 HandBrakeCLI --encoder-encoder-fallback \
                    -e vce_h264 \
                    -q 22 \
                    -w 1280 -l 720 \
                    --audio-lang-list any \
                    --aencoder copy \
                    -i "$f" \
                    -o "$out"
            fi
        done
    ' _ {} +
    
    echo "=========================================================================="
    echo "Proceso finalizado. Revisa la carpeta '$CARPETA_DESTINO'."
    echo "=========================================================================="

    Cómo funciona cada parte

    find + exec: procesar archivos en lote de forma segura

    find . -type f \( -name "*.mp4" -o ... \) -exec sh -c '...' _ {} + busca recursivamente todos los archivos de video con esas extensiones, y en vez de ejecutar el comando una vez por archivo (lo cual sería lento con bibliotecas grandes), usa -exec ... + para agrupar múltiples archivos en menos invocaciones del subshell. El sh -c '...' _ {} + es el patrón estándar para pasar una lista de archivos a un script embebido dentro de find, donde _ ocupa el lugar de $0 (el nombre del script, no usado aquí) y {} se expande a la lista real de archivos encontrados.

    ffprobe: detectar la resolución sin decodificar el video completo

    ffprobe -v error -select_streams v:0 -show_entries stream=width -of default=nw=1:nk=1 "$f"

    ffprobe (parte del proyecto ffmpeg) lee únicamente los metadatos del contenedor de video, sin decodificar los fotogramas — esto lo hace extremadamente rápido incluso en archivos grandes. -select_streams v:0 apunta específicamente al primer stream de video (ignorando pistas de audio o subtítulos embebidos), -show_entries stream=width pide solo el ancho en píxeles, y -of default=nw=1:nk=1 formatea la salida como un valor plano, sin encabezados ni etiquetas — listo para asignarse directamente a una variable de Bash.

    Filtrar solo videos de 1080p o superior

    La condición [ "$w" -ge 1920 ] compara el ancho detectado contra 1920 píxeles (el ancho estándar de 1080p) — cualquier video ya en 720p o menor se salta automáticamente, evitando procesar (y perder calidad innecesariamente) contenido que ya está en una resolución igual o menor a la deseada.

    Protección contra interrupciones

    La verificación if [ -f "$out" ]; then ... continue; fi es clave para bibliotecas grandes que pueden tardar horas en procesarse: si el script se interrumpe (por un corte de energía, un cierre accidental de la terminal) y se vuelve a ejecutar, salta automáticamente los archivos que ya fueron convertidos exitosamente, retomando el trabajo donde quedó sin reprocesar nada innecesariamente.

    HandBrakeCLI: los parámetros de codificación

    ParámetroFunción
    -e vce_h264Usa el encoder por hardware VCE (Video Coding Engine) de AMD para H.264, en vez del encoder por software (x264) — mucho más rápido, a costa de una eficiencia de compresión ligeramente menor
    -q 22Factor de calidad constante (menor número = mayor calidad y mayor tamaño de archivo). 22 es un valor moderado, buen balance para HD
    -w 1280 -l 720Fuerza el ancho y alto de salida a 720p exacto
    --audio-lang-list anyIncluye todas las pistas de audio disponibles, sin filtrar por idioma
    --aencoder copyCopia el audio original sin recodificarlo — solo se recomprime el video, preservando la calidad de audio intacta y acelerando el proceso al evitar una recodificación innecesaria

    Aceleración por hardware: por qué usar la GPU

    Codificar video en H.264 por software (usando la CPU) es una tarea intensiva que puede tardar varias veces la duración real del video, especialmente en equipos sin muchos núcleos. Las GPUs modernas (AMD VCE, Intel Quick Sync, NVIDIA NVENC) tienen bloques de hardware dedicados específicamente para codificación/decodificación de video, capaces de procesar la misma tarea en una fracción del tiempo — el costo es una eficiencia de compresión ligeramente menor a igual calidad percibida, comparado con encoders por software altamente optimizados como x264 en su configuración más lenta.

    nice -n 19: prioridad mínima de CPU

    nice -n 19 ejecuta el proceso con la prioridad de CPU más baja posible en Linux (el rango va de -20, máxima prioridad, a 19, mínima). Aunque la codificación se hace principalmente en la GPU, el proceso HandBrakeCLI sigue usando CPU para tareas de coordinación, demuxing y manejo de audio — nice -n 19 asegura que esas tareas cedan el paso a cualquier otra aplicación que esté usando el equipo activamente en primer plano, dejando la conversión corriendo en segundo plano sin afectar la experiencia de uso normal de la máquina.

    Notas

    • El script mantiene el archivo original intacto — el resultado se guarda en ./Pelis_720p/ con el sufijo _converted, por lo que la limpieza de los originales (si se desea liberar espacio) debe hacerse manualmente después de verificar la calidad del resultado.
    • --encoder-encoder-fallback permite que HandBrake recurra al encoder por software si la GPU no está disponible o falla, evitando que el script se detenga por completo ante un problema puntual con el driver de video.
    • Este enfoque es ideal para bibliotecas grandes de video donde se prioriza velocidad de conversión y ahorro de espacio en disco por encima de exprimir al máximo la eficiencia de compresión.