npm package: @groundbrick/email-service
Description: Serviço de Email plugável com suporte a múltiplos provedores (GatewayAPI, SMTP, etc)
Author: Cleiton Marques
Latest version: 1.2.0

# @groundbrick/email-service

Serviço de email plugável com suporte a múltiplos provedores (GatewayAPI, SMTP, etc.) para TypeScript/Node.js.

## Características

- 📧 **Múltiplos Providers**: GatewayAPI, Sweego, Mock, Redirect
- 🔄 **Múltiplas Instâncias**: Diferente do sms-service, permite múltiplas configurações
- 🎯 **Webhooks**: Suporte completo para webhooks de entrega
- 📝 **Templates**: Variáveis dinâmicas em HTML/texto/subject
- 📊 **Tracking**: Rastreamento de aberturas e cliques (GatewayAPI)
- 📎 **Anexos**: Suporte a anexos com base64
- 🔒 **Type-Safe**: 100% TypeScript com tipos completos
- 🧪 **Testável**: Mock e Redirect providers para desenvolvimento

## Instalação

```bash
npm install @groundbrick/email-service
# ou
pnpm add @groundbrick/email-service
```

## Uso Básico

### GatewayAPI Provider (Produção)

```typescript
import { EmailService } from '@groundbrick/email-service';

const emailService = new EmailService({
  provider: 'gatewayapi',
  config: {
    token: process.env.GATEWAYAPI_EMAIL_TOKEN!,
    defaultFrom: {
      address: 'noreply@example.com',
      name: 'My App'
    },
    webhookSecret: process.env.GATEWAYAPI_WEBHOOK_SECRET // opcional
  }
});

// Enviar email simples
const result = await emailService.send({
  to: { address: 'user@example.com', name: 'John Doe' },
  subject: 'Welcome!',
  html: '<h1>Hello!</h1><p>Welcome to our app.</p>',
  text: 'Hello! Welcome to our app.'
});

console.log(result.messageId); // "123456"
```

### Sweego Provider (Produção)

```typescript
import { EmailService } from '@groundbrick/email-service';

const sweegoEmailService = new EmailService({
  provider: 'sweego',
  config: {
    apiKey: process.env.SWEEGO_API_KEY!, // ou defina accessToken para usar Bearer
    defaultFrom: {
      address: 'noreply@example.com',
      name: 'My App'
    },
    clientId: process.env.SWEEGO_CLIENT_ID, // opcional, repassa para o cabeçalho client-id
    webhookSecret: process.env.SWEEGO_WEBHOOK_SECRET // opcional, Base64 para validar webhooks
  }
});

await sweegoEmailService.send({
  to: { address: 'user@example.com', name: 'John Doe' },
  subject: 'Welcome!',
  html: '<h1>Hello!</h1><p>Welcome to our app.</p>',
  metadata: {
    sweego: {
      campaignId: 'welcome-2025',
      campaignTags: ['welcome'],
      dryRun: false
    }
  }
});
```

Use a chave `metadata.sweego` para acessar recursos específicos da API da Sweego
(campanhas, headers customizados, list-unsubscribe, variáveis por destinatário, etc.).
Veja a seção [Sweego](#sweego) para a lista completa dos campos suportados.

### Mock Provider (Testes)

```typescript
const emailService = new EmailService({
  provider: 'mock',
  config: {
    defaultFrom: { address: 'test@example.com' },
    simulateDelay: 100, // ms
    simulateFailures: false // ou true para 10% de falhas
  }
});

const result = await emailService.send({...});

// Acessar emails enviados (apenas Mock)
import { MockEmailProvider } from '@groundbrick/email-service';
const mock = emailService['provider'] as MockEmailProvider;
const sentEmails = mock.getSentEmails();
```

### Redirect Provider (Desenvolvimento)

Redireciona TODOS os emails para um endereço específico:

```typescript
const emailService = new EmailService({
  provider: 'redirect',
  config: {
    redirectTo: 'dev@example.com',
    defaultFrom: { address: 'noreply@example.com' },
    addOriginalToSubject: true // adiciona destinatários originais no subject
  }
});

// Este email será redirecionado para dev@example.com
await emailService.send({
  to: { address: 'customer@example.com' },
  subject: 'Order Confirmation',
  html: '<p>Your order is confirmed!</p>'
});
// Subject real: "[REDIRECTED] Order Confirmation (Original: customer@example.com)"
```

## Funcionalidades Avançadas

### Múltiplos Destinatários (CC, BCC)

```typescript
await emailService.send({
  to: [
    { address: 'user1@example.com', name: 'User 1' },
    { address: 'user2@example.com' }
  ],
  cc: [{ address: 'manager@example.com' }],
  bcc: [{ address: 'archive@example.com' }],
  subject: 'Meeting Tomorrow',
  html: '<p>Don\'t forget our meeting!</p>'
});
```

### Anexos

```typescript
await emailService.send({
  to: { address: 'user@example.com' },
  subject: 'Invoice #1234',
  html: '<p>Your invoice is attached.</p>',
  attachments: [
    {
      filename: 'invoice.pdf',
      content: pdfBuffer, // Buffer ou string
      contentType: 'application/pdf'
    }
  ]
});
```

### Templates com Variáveis

```typescript
await emailService.send({
  to: { address: 'user@example.com' },
  subject: 'Hello %firstname!',
  html: '<p>Hi %firstname %lastname, your code is %code.</p>',
  template: {
    variables: {
      firstname: 'John',
      lastname: 'Doe',
      code: '123456'
    }
  }
});
```

### Tracking de Opens/Clicks (GatewayAPI)

```typescript
await emailService.send({
  to: { address: 'user@example.com' },
  subject: 'Newsletter',
  html: '<p>Check out our <a href="https://example.com">website</a>!</p>',
  tracking: {
    opens: true,
    clicks: true
  }
});
```

### Metadados específicos do Sweego

Quando estiver usando o provider `sweego`, utilize `metadata.sweego` para ativar
opções exclusivas da API:

```typescript
await sweegoEmailService.send({
  to: { address: 'user@example.com' },
  subject: 'Welcome',
  html: '<p>Hello!</p>',
  metadata: {
    sweego: {
      campaignId: 'welcome-2025',
      campaignTags: ['welcome', 'prod'],
      campaignType: 'transac',
      headers: { 'x-custom-header': 'value' },
      listUnsub: { method: 'one-click', value: 'mailto:unsubscribe@example.com,https://example.com/unsub' },
      dryRun: false,
      expires: '2025-12-31T23:59:59Z',
      clientId: 'my-client',
      variables: { name: 'John' }
    }
  }
});
```

Campos suportados em `metadata.sweego`:

- `campaignId`, `campaignTags` e `campaignType`
- `headers` (até 5 cabeçalhos customizados)
- `listUnsub` (`{ method?: 'mailto' | 'one-click'; value: string }`)
- `dryRun` e `expires`
- `variables` ou `perRecipientVariables` (array de objetos na mesma ordem dos destinatários)
- `clientId`, `channel` e `provider` (casos multi-provedor na mesma conta)

### Delivery Reports

```typescript
const result = await emailService.send({...});

// Consultar status depois
const report = await emailService.getDeliveryReport(result.messageId!);

console.log(report?.status); // 'delivered', 'bounced', 'failed', etc.
```

### Webhooks

```typescript
// Middleware para manter o raw body (necessário para Sweego)
const rawJson = express.json({
  verify: (req, _res, buf) => {
    req.rawBody = buf.toString('utf8');
  }
});

app.post('/api/webhooks/email', rawJson, (req, res) => {
  const signature = req.headers['authorization'] || '';

  const validation = emailService.validateWebhook(req.body, signature, {
    headers: req.headers as Record<string, string | string[]>,
    rawBody: req.rawBody // Sweego precisa do corpo original para validar o HMAC
  });

  if (validation.isValid && validation.payload) {
    const report = validation.payload;
    console.log(`Email ${report.messageId} status: ${report.status}`);
  }

  res.sendStatus(200);
});
```

> 💡 **Sweego:** defina `webhookSecret` (string em Base64) no config e garanta que as
> headers `webhook-id`, `webhook-timestamp` e `webhook-signature` sejam
> repassadas para `validateWebhook` através do parâmetro `headers`.

## Configuração por Ambiente

```typescript
const emailService = new EmailService({
  provider: process.env.NODE_ENV === 'production' ? 'gatewayapi' : 'redirect',
  config: process.env.NODE_ENV === 'production'
    ? {
        token: process.env.GATEWAYAPI_EMAIL_TOKEN!,
        defaultFrom: { address: 'noreply@myapp.com', name: 'MyApp' }
      }
    : {
        redirectTo: process.env.DEV_EMAIL || 'dev@myapp.com',
        defaultFrom: { address: 'noreply@myapp.com', name: 'MyApp [DEV]' }
      }
});
```

## API Reference

### EmailService

```typescript
class EmailService {
  constructor(config: EmailConfig)
  send(message: EmailMessage): Promise<EmailResult>
  getDeliveryReport(messageId: string): Promise<DeliveryReport | null>
  validateWebhook(
    payload: any,
    signature?: string,
    options?: WebhookValidationOptions
  ): WebhookValidationResult
}
```

```typescript
interface WebhookValidationOptions {
  headers?: Record<string, string | string[] | undefined>;
  rawBody?: string;
}
```

### EmailMessage

```typescript
interface EmailMessage {
  to: EmailAddress | EmailAddress[]
  from?: EmailAddress
  cc?: EmailAddress[]
  bcc?: EmailAddress[]
  replyTo?: EmailAddress
  subject: string
  text?: string
  html?: string
  attachments?: EmailAttachment[]
  template?: EmailTemplate
  tracking?: EmailTracking
  metadata?: Record<string, any>
}
```

### EmailStatus

```typescript
enum EmailStatus {
  QUEUED = 'queued',
  SENT = 'sent',
  DELIVERED = 'delivered',
  BOUNCED = 'bounced',
  FAILED = 'failed',
  DEFERRED = 'deferred',
  BLOCKED = 'blocked'
}
```

## GatewayAPI

Para usar o GatewayAPI:

1. Obtenha um token em [GatewayAPI](https://gatewayapi.com)
2. Configure webhook (opcional) para receber notificações de entrega
3. Use o token no config:

```typescript
const emailService = new EmailService({
  provider: 'gatewayapi',
  config: {
    token: 'your-token-here',
    baseUrl: 'https://gatewayapi.com', // opcional
    webhookSecret: 'your-webhook-secret', // opcional, para validação JWT
    defaultFrom: { address: 'noreply@example.com' }
  }
});
```

### Limites GatewayAPI

- Anexos: Máximo 5MB total
- Rate limits: Conforme seu plano

## Sweego

1. Crie um API Key ou OAuth Client em [app.sweego.io](https://app.sweego.io/)
2. Configure e verifique um subdomínio dedicado para envio
3. Copie o segredo do webhook (menu **Webhooks**) e salve a versão Base64 no
   `webhookSecret`

```typescript
const emailService = new EmailService({
  provider: 'sweego',
  config: {
    apiKey: process.env.SWEEGO_API_KEY!, // ou use accessToken
    clientId: process.env.SWEEGO_CLIENT_ID,
    defaultFrom: { address: 'noreply@example.com', name: 'My App' },
    webhookSecret: process.env.SWEEGO_WEBHOOK_SECRET
  }
});
```

### Opções suportadas

- `apiKey` **ou** `accessToken` (Bearer)
- `clientId` para definir o cabeçalho `client-id`
- `baseUrl`, `channel` e `providerSlug` (casos de sandbox)
- `webhookSecret` (Base64) para validar `webhook-id/webhook-timestamp/webhook-signature`

Use `metadata.sweego` para configurar campanhas, headers, dry-run, variáveis e
list-unsubscribe. Documentação oficial: [envio por API](https://learn.sweego.io/docs/sending/how_to_send_email_by_api) e
[assinatura de webhook](https://learn.sweego.io/docs/webhooks/webhook_signature).

## Migração do Service-Base

Veja [MIGRATION.md](./MIGRATION.md) para guia completo de migração do antigo `@groundbrick/service-base`.

## Licença

MIT