@hemia/workflow-node-email
v0.0.2
Published
Nodo de email para Hemia Workflow: envía correos electrónicos basados en eventos.
Downloads
6
Readme
@hemia/workflow-node-email
Nodo de envío de correos para Hemia Workflow. Permite enviar emails usando un servicio inyectado, con soporte de plantillas, datos dinámicos, adjuntos y cabeceras. Aprovecha la interpolación del engine para ${config.*} y {{ ... }} (JEXL).
Instalación
npm install @hemia/workflow-node-emailRegistro en el engine
import { NodeRegistry } from '@hemia/workflow-engine';
import { emailNode } from '@hemia/workflow-node-email';
const registry = new NodeRegistry();
registry.register('email', emailNode);Requisitos de ejecución
Este nodo espera un EmailService inyectado en el contexto:
- variables.emailService, o
- variables.services.email
Interfaz mínima esperada:
interface EmailService {
send(options: {
to: string[]; subject: string; html?: string; text?: string;
template?: string; data?: Record<string, any>;
from?: string; cc?: string[]; bcc?: string[]; replyTo?: string;
headers?: Record<string, string>;
attachments?: Array<{ filename: string; content: string; contentType?: string; encoding?: string }>;
}): Promise<{ id: string; provider?: any }>;
}Uso en un workflow
Ejemplo básico con plantilla y datos dinámicos:
{
"id": "vacation-request-flow",
"name": "Solicitud de Vacaciones",
"config": {
"email": { "from": "[email protected]" },
"timeouts": { "http": "30s" }
},
"steps": [
{
"id": "notifyManager",
"type": "email",
"params": {
"to": "{{ context.userId | getManagerEmail }}",
"from": "${config.email.from}",
"subject": "Solicitud de vacaciones pendiente",
"template": "vacation-request-approval",
"data": {
"employee": "{{context.userFullName}}",
"startDate": "{{input.startDate}}",
"endDate": "{{input.endDate}}",
"reason": "{{input.reason}}",
"approvalUrl": "{{ request.data.id | generateApprovalUrl }}"
},
"saveAs": "notifyEmail"
},
"next": [{ "id": "waitApproval" }],
"error": { "next": "handleError" }
}
]
}Ejemplo con CC/BCC y adjuntos:
{
"id": "emailWithAttachments",
"type": "email",
"params": {
"to": ["[email protected]"],
"cc": ["[email protected]"],
"bcc": ["[email protected]"],
"from": "${config.email.from}",
"subject": "Detalle de solicitud",
"html": "<p>Hola {{context.userFullName}}, adjuntamos el detalle.</p>",
"attachments": [
{ "filename": "resumen.pdf", "content": "{{output_generatePdf.base64}}", "contentType": "application/pdf", "encoding": "base64" }
],
"saveAs": "emailSummary"
},
"error": { "next": "handleError" }
}Ejemplo usando texto plano (sin plantilla):
{
"id": "plainTextEmail",
"type": "email",
"params": {
"to": "{{input.email}}",
"subject": "Recibimos tu solicitud",
"text": "Hola {{input.employeeName}}, tu solicitud de vacaciones fue registrada."
}
}Parámetros
- to: string | string[] (requerido). Destinatarios. Acepta coma separada en string.
- from?: string. Remitente; si no se envía, puedes resolverlo desde ${config.email.from}.
- subject: string (recomendado). Asunto del email.
- template?: string. Identificador de plantilla a resolver por tu EmailService.
- data?: object. Datos para la plantilla (interpolables con JEXL).
- html?: string. Cuerpo HTML alternativo si no usas template.
- text?: string. Cuerpo texto plano.
- cc?: string | string[]. Copia.
- bcc?: string | string[]. Copia oculta.
- replyTo?: string. Responder a.
- headers?: object. Cabeceras adicionales.
- attachments?: Array<{ filename, content, contentType?, encoding? }>.
- saveAs?: string. Si se define y el envío es exitoso, el nodo guarda la salida en variables[saveAs].
Notas:
- Interpolación soportada:
- ${config.*} desde workflow.config (p. ej., ${config.email.from})
- {{ ... }} con JEXL sobre variables/context (p. ej., {{context.userId}})
- Manejo de errores: puedes encadenar con "error.next" hacia un handler o usar workflow.errorHandlers.
Salida (output)
En caso de éxito:
{
"results": {
"id": "email_123",
"to": ["[email protected]"]
},
"provider": { "messageId": "sg-abc123" }
}- Si definiste "saveAs": "notifyEmail", encontrarás esa salida en variables.notifyEmail.
- El engine también guardará output del paso en variables.output_.
En caso de error:
{
"success": false,
"error": { "code": "EMAIL_FAILED", "message": "Descripción", "details": { } }
}Integración del EmailService
Ejemplo de inyección en el contexto:
// Al cargar el contexto de una ejecución
const loadContext = async () => ({
variables: {
config: { email: { from: "[email protected]" } },
services: { email: myEmailService }, // o variables.emailService = myEmailService
context: { userId: "E-1001", userFullName: "Ana Pérez" }
}
});Buenas prácticas
- Centraliza el remitente en config.email.from y evita hardcodear emails.
- Usa transforms JEXL para datos derivados (p. ej., getManagerEmail, generateApprovalUrl).
- Maneja errores con error.next y un handler HTTP global para observabilidad.
- Agrega unit tests del nodo y mocks del EmailService.
Scripts
- npm run build: compila el paquete.
- npm run test: ejecuta pruebas.
- npm run lint: lint del código.
