Skip to content

Newsletter Subscription Backend

Backend implementation for the newsletter subscription feature that integrates with Brevo for list management and Resend for welcome emails.

Architecture

API Endpoint

Route: POST /newsletter/subscribe

Controller: SubscriptionsController.subscribe()

Location: apps/server/app/controllers/subscriptions_controller.ts

Service Layer

The system uses two main services:

  1. BrevoService - Newsletter list management
  2. ResendService - Transactional email delivery

Data Flow

User Input → Validation → Brevo (List) → Resend (Welcome Email) → Success Response

Implementation

Controller

typescript
export default class SubscriptionsController {
  async subscribe({ request, response }: HttpContext) {
    const { email } = await request.validateUsing(subscribeValidator)

    try {
      // Add to Brevo mailing list
      await BrevoService.addSubscriber(email, listId)

      // Send welcome email via Resend
      await ResendService.sendWelcomeEmail(email)

      return response.created(
        renderSuccessResponsePayload({
          message: 'Successfully subscribed to the newsletter.',
        })
      )
    } catch (error) {
      // Handle errors appropriately
    }
  }
}

Validation

Email validation is handled by apps/server/app/validators/subscription.ts:

typescript
export const subscribeValidator = vine.compile(
  vine.object({
    email: vine.string().email().trim(),
  })
)

Error Handling

The system handles several error scenarios:

  1. Duplicate Subscribers - Returns 409 Conflict
  2. Invalid Email - Returns 400 Bad Request
  3. Service Errors - Returns 500 Internal Server Error

Email Services

The newsletter subscription feature uses the Email Infrastructure for:

  • Brevo - Subscriber list management and newsletter campaigns
  • Resend - Welcome email delivery and transactional emails

For detailed configuration and service information, see the Email Infrastructure documentation.

Email Templates

Welcome Email

Template: apps/server/resources/views/emails/welcome.edge

Features:

  • Responsive design
  • Branded styling
  • Clear call-to-action
  • Unsubscribe link

Content Structure:

html
<!DOCTYPE html>
<html>
  <head>
    <title>Welcome to Jubiloop!</title>
  </head>
  <body>
    <h1>Welcome to Jubiloop!</h1>
    <p>Thank you for joining our early access list...</p>
    <!-- More content -->
  </body>
</html>

Environment Configuration

Development

bash
# Brevo Configuration
BREVO_API_KEY=dev_brevo_api_key
BREVO_NEWSLETTER_SUBSCRIBER_LIST_ID=dev_list_id

# Resend Configuration
RESEND_API_KEY=dev_resend_api_key
RESEND_FROM_NAME=Jubiloop Dev Team
RESEND_FROM_EMAIL=noreply@dev.jubiloop.ca

QA

bash
# Brevo Configuration
BREVO_API_KEY=qa_brevo_api_key
BREVO_NEWSLETTER_SUBSCRIBER_LIST_ID=qa_list_id

# Resend Configuration
RESEND_API_KEY=qa_resend_api_key
RESEND_FROM_NAME=Jubiloop QA Team
RESEND_FROM_EMAIL=noreply@qa.jubiloop.ca

Production

bash
# Brevo Configuration
BREVO_API_KEY=prod_brevo_api_key
BREVO_NEWSLETTER_SUBSCRIBER_LIST_ID=prod_list_id

# Resend Configuration
RESEND_API_KEY=prod_resend_api_key
RESEND_FROM_NAME=Jubiloop Team
RESEND_FROM_EMAIL=noreply@jubiloop.ca

API Reference

Subscribe Endpoint

POST /newsletter/subscribe

Request Body:

json
{
  "email": "user@example.com"
}

Success Response (201):

json
{
  "success": true,
  "message": "Successfully subscribed to the newsletter."
}

Error Responses:

400 Bad Request (Invalid Email):

json
{
  "success": false,
  "errorMessage": "Validation failed",
  "errors": {
    "email": ["The email field must be a valid email address"]
  }
}

409 Conflict (Duplicate Subscriber):

json
{
  "success": false,
  "errorMessage": "This email is already subscribed to the newsletter."
}

500 Internal Server Error:

json
{
  "success": false,
  "errorMessage": "Failed to subscribe to the newsletter."
}

Testing

Manual Testing

Test Valid Subscription:

bash
curl -X POST http://localhost:3333/newsletter/subscribe \
  -H "Content-Type: application/json" \
  -d '{"email":"test@example.com"}'

Test Invalid Email:

bash
curl -X POST http://localhost:3333/newsletter/subscribe \
  -H "Content-Type: application/json" \
  -d '{"email":"invalid-email"}'

Test Duplicate Subscription:

bash
# Run the same email twice
curl -X POST http://localhost:3333/newsletter/subscribe \
  -H "Content-Type: application/json" \
  -d '{"email":"duplicate@example.com"}'

Automated Testing

Currently, there are no automated tests for the newsletter subscription feature. Tests should be added for:

  • Email validation logic
  • Controller response handling
  • Brevo/Resend service integration
  • Error handling scenarios

Monitoring

Logging

The system logs all subscription attempts:

typescript
logger.info('Newsletter subscription attempt', { email })
logger.error('Newsletter subscription failed', { error, email })

Metrics to Track

  1. Subscription Volume

    • Daily signup count
    • Hourly signup patterns
    • Geographic distribution
  2. Success Rates

    • Validation success rate
    • Brevo integration success rate
    • Resend delivery success rate
  3. Error Rates

    • Invalid email attempts
    • Duplicate subscription attempts
    • Service integration failures

Health Checks

Monitor service health through:

bash
# Check Brevo connectivity
curl -H "Authorization: Bearer $BREVO_API_KEY" \
  https://api.brevo.com/v3/contacts

# Check Resend connectivity
curl -H "Authorization: Bearer $RESEND_API_KEY" \
  https://api.resend.com/domains

Security

Input Validation

  • Email format validation
  • Rate limiting (future enhancement)
  • XSS protection via Edge templates

Data Protection

  • Email addresses stored securely
  • GDPR compliance considerations
  • Unsubscribe functionality

API Security

  • CORS configuration
  • Request size limits
  • Error message sanitization

Troubleshooting

Common Issues

Brevo API Errors:

  1. Check API key validity
  2. Verify list ID exists
  3. Check API rate limits

Resend Delivery Failures:

  1. Verify sender email domain
  2. Check email content
  3. Monitor bounce rates

Validation Errors:

  1. Check email format
  2. Verify request structure
  3. Review validation rules

Debug Commands

bash
# Check environment variables
echo $BREVO_API_KEY
echo $RESEND_API_KEY

# Test Brevo connection
curl -H "Authorization: Bearer $BREVO_API_KEY" \
  https://api.brevo.com/v3/contacts

# Test Resend connection
curl -H "Authorization: Bearer $RESEND_API_KEY" \
  https://api.resend.com/emails

# Check server logs
docker logs server | grep subscription

Future Enhancements

Planned Features

  1. Double Opt-in - Email verification before subscription
  2. Rate Limiting - Prevent abuse of signup endpoint
  3. Analytics Integration - Track conversion rates
  4. A/B Testing - Test different email templates
  5. Segmentation - Group subscribers by interests

Technical Improvements

  1. Queue System - Async email processing
  2. Retry Logic - Handle temporary service failures
  3. Webhook Support - Real-time delivery status
  4. Template Management - Dynamic email templates
  5. Unsubscribe API - Programmatic unsubscribe endpoint

Built with ❤️ by the Jubiloop team