A full-stack email operations dashboard built for Orion Tech Community to manage transactional and operational email workflows.
Orion Team Mail Worker combines a React-based administration dashboard, an Express API, Supabase/PostgreSQL data storage, a database-backed email queue, reusable HTML templates, and Brevo for email delivery.
The system is designed to centralize email sending, queue management, template administration, delivery history, logging, and sender configuration in a single application.
Orion Team Mail Worker is the email infrastructure used by Orion Tech Community to handle both automated and manually triggered email communication.
Instead of sending every message directly from application features, the system can place emails into a persistent queue and process them through a dedicated worker flow.
This approach provides:
- Persistent email queue management
- Retry handling for temporary delivery failures
- Daily sending limits
- Email template management
- Dynamic template placeholders
- Manual email composition
- Recipient search across community members and speakers
- Delivery history
- Sending logs
- Email previews
- Configurable sender identity
- Brevo API integration
- Supabase/PostgreSQL persistence
Emails can be inserted into a persistent email_queue table and processed according to their priority and current delivery state.
Each queue item contains information such as:
- Recipient email
- Recipient name
- Template code
- Template parameters
- Priority
- Status
- Attempt count
- Last attempt time
- Sent time
- Error message
- Brevo message ID
- Creation/update timestamps
Supported queue states:
pending
sent
failed
Queue processing prioritizes emails using:
high
medium
low
Older messages are processed first within the same priority level.
The worker keeps track of delivery attempts for every queued email.
Retry behavior is based on the type of Brevo/API failure:
- 4xx responses: treated as non-retryable client errors
- 5xx responses: treated as retryable server errors
- Network errors / timeouts: retryable
- Maximum attempts are controlled through the
retry_limitsetting
This prevents permanently invalid requests from being retried indefinitely while still allowing temporary infrastructure failures to recover automatically.
The worker checks the number of emails sent during the current day before processing the queue.
The configurable daily limit is stored in email_settings:
daily_limit
The dashboard exposes the current usage and displays the relationship between:
emails sent today / daily limit
This helps prevent the queue processor from exceeding the configured sending capacity.
Email templates are stored in the email_templates table and can be managed from the dashboard.
Supported operations include:
Create
Read
Update
Delete
Templates contain:
- Template name
- Template code
- Optional Brevo template ID
- Subject
- HTML content
- Active/inactive state
Templates support dynamic variables using the following syntax:
{{member_name}}
{{project_name}}
{{event_name}}
{{event_date}}For example:
<h1>Welcome {{member_name}}!</h1> <p> You have joined the {{project_name}} project. </p>
During processing, placeholders are replaced using the parameters stored with the queue item.
The application defines a set of system-level template codes used by Orion Tech Community workflows.
Current system templates include:
welcome_member
task_assigned
project_member
department_member
area_member
member_area_assigned
speaker_invite
event_speaker
event_staff_member
announcement_general
announcement_member
birthday_personal
birthday_team
System templates are protected from deletion and their template codes cannot be changed because application workflows depend on those identifiers.
The project includes a lightweight template rendering engine located in:
src/lib/templateEngine.ts
It provides:
{{variable}}
Template placeholders can also be used inside subject lines.
Before an email is sent, its HTML content can be wrapped inside a consistent Orion-branded email layout.
The generated layout includes:
- Header
- Optional sender logo
- Sender name
- Email body
- Optional website
- Optional sender address
- Footer
- Current year
This keeps email formatting consistent across different application workflows.
The dashboard includes a Gmail-style compose interface for sending emails manually.
The compose flow supports:
- Multiple recipients
- CC recipients
- Internal community members
- Speakers
- External email addresses
- Email templates
- Subject editing
- HTML message content
- Direct sending
- Queue-based sending
The recipient component searches Supabase for active:
members
speakers
Users can search by:
name
email
External addresses can also be entered manually.
For example:
Pressing Enter or using a comma can add an external address to the recipient list.
The compose screen supports two different delivery workflows.
The message is sent immediately through the Express API and Brevo.
Endpoint:
POST /api/compose/send
The operation is also recorded in:
manual_emails
The response contains per-recipient delivery results and Brevo message IDs.
Instead of sending immediately, the message can be placed into:
email_queue
Endpoint:
POST /api/queue/enqueue-manual
The queue processor can then process the message according to:
- Priority
- Retry rules
- Daily limits
- Template configuration
- Email system state
This mode is useful when email delivery should be separated from the user action that created the message.
The React dashboard provides a centralized operational interface.
Main sections include:
Dashboard
Compose
Templates
Logs
Settings
The dashboard displays:
- Pending emails
- Total sent emails
- Total failed emails
- Emails sent today
- Daily sending limit
- Last successful send time
The queue table also supports:
- Status filtering
- Pagination
- Manual sending
- Queue item deletion
- Queue item detail inspection
- Rendered email preview
Individual queue items can be inspected through:
GET /api/queue/:id/detail
The endpoint returns the rendered email content together with delivery metadata.
The detail response includes:
id
status
created_at
sent_at
error_message
recipient_email
recipient_name
subject
html_content
The dashboard can display the rendered email in an isolated preview frame.
Every queue delivery attempt can be recorded in:
email_send_logs
Log records contain information such as:
- Queue item ID
- Recipient
- Template code
- Event type
- Attempt number
- Error information
- Brevo message ID
- Timestamp
The dashboard exposes the latest delivery records through the Logs panel.
Supported delivery events currently include:
sent
failed
Sender configuration is stored in the email_settings table.
The dashboard provides configuration for:
| Setting | Description |
|---|---|
brevo_api_key |
Brevo API key |
sender_email |
Sender email address |
sender_name |
Sender display name |
sender_logo_url |
Optional email header logo |
sender_website |
Optional sender website |
sender_address |
Optional footer address |
daily_limit |
Maximum number of emails per day |
retry_limit |
Maximum delivery attempts |
enabled |
Enables/disables email processing |
The settings are represented internally by the EmailSettings type.
The Express backend exposes the following endpoints.
GET /health
Returns a simple service health response:
{
"ok": true
}POST /api/compose/send
Sends an email immediately through Brevo.
GET /api/compose/history
Supports pagination through:
page
limit
A history entry can also be deleted:
DELETE /api/compose/history/:id
Add manually composed email messages to the queue:
POST /api/queue/enqueue-manual
Send a specific queued email:
POST /api/queue/:id/send
Delete a queued email:
DELETE /api/queue/:id
Inspect a queued email:
GET /api/queue/:id/detail
List templates:
GET /api/templates
Get a template:
GET /api/templates/:id
Create a template:
POST /api/templates
Update a template:
PATCH /api/templates/:id
Delete a template:
DELETE /api/templates/:id
Template creation and update operations validate template names, codes, subjects, and HTML content.
The project follows a simple full-stack separation:
┌─────────────────────────────────────┐
│ React Dashboard │
│ │
│ Queue │ Compose │ Templates │ Logs │
│ Settings │
└─────────────────┬───────────────────┘
│
│ HTTP / Supabase
▼
┌─────────────────────────────────────┐
│ Express API Layer │
│ │
│ composeSend │
│ composeHistory │
│ queueEnqueueManual │
│ queueSend │
│ queueDetail │
│ templates │
└─────────────────┬───────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Supabase DB │
│ │
│ email_queue │
│ email_templates │
│ email_settings │
│ email_send_logs │
│ manual_emails │
│ members │
│ speakers │
└─────────────────┬───────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Brevo API │
│ │
│ Email Delivery │
└─────────────────────────────────────┘
OrionTeamMailWorker/
│
├── src/
│ ├── components/
│ │ ├── ComposeEditor.tsx
│ │ ├── ComposeForm.tsx
│ │ ├── MailHistoryTable.tsx
│ │ ├── QueueTable.tsx
│ │ ├── TemplatesPanel.tsx
│ │ ├── TemplateForm.tsx
│ │ ├── TemplatePreview.tsx
│ │ ├── SettingsPanel.tsx
│ │ ├── LogsPanel.tsx
│ │ ├── RecipientInput.tsx
│ │ ├── TriggerButton.tsx
│ │ └── ...
│ │
│ ├── lib/
│ │ ├── brevo.ts
│ │ ├── worker.ts
│ │ ├── templateEngine.ts
│ │ ├── settingsLoader.ts
│ │ ├── supabaseClient.ts
│ │ ├── useTemplateActions.ts
│ │ └── types.ts
│ │
│ ├── utils/
│ │ └── cn.ts
│ │
│ ├── App.tsx
│ ├── main.tsx
│ └── index.css
│
├── server/
│ ├── lib/
│ │ ├── supabase.ts
│ │ └── settingsLoader.ts
│ │
│ ├── routes/
│ │ ├── composeSend.ts
│ │ ├── composeHistory.ts
│ │ ├── queueEnqueueManual.ts
│ │ ├── queueSend.ts
│ │ ├── queueDetail.ts
│ │ └── templates.ts
│ │
│ └── index.ts
│
├── IMPLEMENTATION_SUMMARY.md
├── TEMPLATE_UPDATE_GUIDE.md
├── TEMPLATE_UPDATE_QUICK_REF.md
├── TODO.md
├── package.json
├── tsconfig.json
├── vite.config.ts
├── vercel.json
└── index.html
- React
- TypeScript
- Vite
- Tailwind CSS
- Lucide React
- Node.js
- Express
- TypeScript
- TSX
- Supabase
- PostgreSQL
- Brevo API
- Zod
- Axios
- Fetch API
- Vercel-compatible frontend build
- Express server runtime
- Vercel Cron configuration
Make sure the following are installed:
- Node.js
- npm
- A Supabase project
- A Brevo account/API key
Clone the repository:
git clone https://github.com/oriontechcommunitydev/OrionTeamMailWorker.git
Enter the project:
cd OrionTeamMailWorkerInstall dependencies:
npm install
The frontend uses Vite environment variables:
VITE_SUPABASE_URL=... VITE_SUPABASE_ANON_KEY=...
The Express backend requires:
SUPABASE_URL=... SUPABASE_SERVICE_ROLE_KEY=...
Do not commit real credentials, service-role keys, or provider secrets to source control.
Email-specific configuration is loaded from the email_settings table.
The application expects the following logical tables:
email_settings
email_queue
email_templates
email_send_logs
manual_emails
It also integrates with community data stored in:
members
speakers
The exact database schema should be configured in the associated Supabase project.
Start the Vite development server:
npm run dev
The frontend runs on:
http://localhost:5173
During development, Vite proxies /api requests to:
http://localhost:3000
Start the backend:
npx tsx server/index.ts
The API server listens on:
http://localhost:3000
Health check:
http://localhost:3000/health
Build the frontend:
npm run build
Start the Express application:
npm start
The Express server serves the generated Vite dist directory together with the API routes.
A typical queue-based delivery flow looks like this:
Application
│
▼
Create email
│
▼
email_queue
│
▼
Queue processor
│
├── Check system settings
├── Check daily limit
├── Select pending messages
├── Respect priority
├── Resolve template
├── Render placeholders
├── Wrap email layout
└── Send through Brevo
│
▼
┌───────────┐
│ Brevo │
└─────┬─────┘
│
┌──────┴──────┐
▼ ▼
Success Error
│ │
▼ ▼
status=sent retry / failed
│ │
└──────┬──────┘
▼
email_send_logs
Templates can be managed directly from the dashboard:
Templates
│
├── Create
├── Search
├── Edit
├── Preview
├── Activate / Deactivate
└── Delete
The editor supports:
- HTML content
- Subject
- Template code
- Optional Brevo Template ID
- Dynamic placeholders
- Live HTML preview
Additional implementation documentation is available in the repository:
TEMPLATE_UPDATE_GUIDE.md
Detailed documentation for template CRUD operations and the template API.
TEMPLATE_UPDATE_QUICK_REF.md
A shorter reference for template-related development.
IMPLEMENTATION_SUMMARY.md
Technical summary of the implemented template update functionality.
TODO.md
Current development tasks and remaining work.
The repository contains both frontend and backend implementations, with some operations currently accessing Supabase directly from React while other operations use the Express API.
The repository also contains a Vercel Cron configuration for:
/api/process-queue
Before relying on scheduled queue processing in a production deployment, verify that this endpoint is exposed by the deployed runtime.
Potential improvements for the project include:
- Moving all queue-processing execution behind a server-side worker endpoint
- Centralizing server-side authorization
- Consolidating direct Supabase access and API access
- Adding automated tests for queue and delivery behavior
- Adding template versioning and rollback support
- Adding email preview/test-send functionality
- Adding delivery analytics
- Adding more granular audit logs
- Improving queue concurrency and locking
- Adding structured logging and monitoring
- Expanding provider support beyond Brevo
Orion Team Mail Worker is developed as part of the technical infrastructure of Orion Tech Community, supporting community operations and automated communication workflows.
The project focuses on making operational email delivery easier to manage, monitor, and extend while keeping templates and delivery configuration centralized.
Active development.
The architecture and functionality described above reflect the current implementation of the repository.
A license has not yet been specified in the repository.