Overview
WAHA Dashboard implements a robust multi-channel notification system using WhatsApp (primary) and email (fallback) to ensure administrators are always informed of critical events. The system is powered by Mailgun for email delivery and the WAHA API for WhatsApp messaging.
Notification Channels
WhatsApp Primary notification channel for real-time alerts
Instant delivery
Rich formatting with emojis
Direct links to admin dashboard
Email Fallback channel when WhatsApp fails
HTML-styled templates
Professional branding
Reliable delivery via Mailgun
Email Configuration
Email notifications use Mailgun as the delivery provider:
const mailgun = new Mailgun ( FormData );
const mg = mailgun . client ({
username: "api" ,
key: env . MAILGUN_API_KEY ,
});
Required Environment Variables
Your Mailgun API key for authentication
Your verified Mailgun sending domain
Sender email address (must be on verified domain)
Administrator email address for notifications
Administrator phone number for WhatsApp notifications (format: 1234567890)
Base URL for your application (used in notification links)
Notification Types
1. User Registration Notifications
When a new user signs up, admins receive dual-channel notifications.
WhatsApp Notification
src/server/mailgun.ts:430
export async function sendWhatsAppNotificationToAdmin ( userName : string , userEmail : string ) {
const admin = await db . user . findFirst ({
where: { role: "ADMIN" },
select: { id: true },
});
const adminSession = await db . whatsAppSession . findFirst ({
where: { userId: admin . id }
});
if ( ! adminSession ) {
throw new Error ( "No active WhatsApp session found for admin" );
}
const message = `🔔 *New User Registration*
A new user has registered for WhatsApp Group Manager:
👤 *Name:* ${ userName }
📧 *Email:* ${ userEmail }
📅 *Date:* ${ new Date (). toLocaleDateString () }
Please review and approve this registration in the admin dashboard.
${ env . BETTER_AUTH_URL } /admin` ;
const response = await fetch ( ` ${ env . WAHA_API_URL } /api/sendText` , {
method: 'POST' ,
headers: {
'accept' : 'application/json' ,
'X-Api-Key' : env . WAHA_API_KEY ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
chatId: env . ADMIN_PHONE_NUMBER + '@c.us' ,
text: message ,
session: adminSession . sessionName ,
})
});
return { success: true };
}
WhatsApp notifications require:
An active admin WhatsApp session
Configured WAHA API endpoint
Valid API key
Admin phone number in E.164 format
Email Notification
src/server/mailgun.ts:286
export async function sendUserRegistrationNotificationToAdmin ( userName : string , userEmail : string ) {
const emailData = {
from: env . FROM_EMAIL ,
to: env . ADMIN_EMAIL ,
subject: "New User Registration - Approval Required" ,
html: `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>New User Registration</title>
</head>
<body>
<div class="container">
<div class="header">
<div class="logo">📱 WhatsApp Group Manager</div>
<div class="notification-icon">🔔</div>
<h1 class="title">New User Registration</h1>
</div>
<div class="content">
<p>Hello Admin,</p>
<p>A new user has registered and is waiting for approval.</p>
<div class="user-details">
<div class="user-detail"><strong>Name:</strong> ${ userName } </div>
<div class="user-detail"><strong>Email:</strong> ${ userEmail } </div>
<div class="user-detail"><strong>Registration Date:</strong> ${ new Date (). toLocaleDateString () } </div>
</div>
<div style="text-align: center;">
<a href=" ${ env . BETTER_AUTH_URL } /admin" class="action-button">
Go to Admin Dashboard
</a>
</div>
</div>
</div>
</body>
</html>
` ,
text: `New User Registration
Name: ${ userName }
Email: ${ userEmail }
Registration Date: ${ new Date (). toLocaleDateString () }
Please review this registration in the admin dashboard.`
};
const response = await mg . messages . create ( env . MAILGUN_DOMAIN , emailData );
return { success: true , messageId: response . id };
}
2. Password Reset Emails
Sent when users request to reset their password:
export async function sendResetPasswordEmail ( email : string , url : string ) {
const emailData = {
from: env . FROM_EMAIL ,
to: email ,
subject: "Reset Your Password - WhatsApp Group Manager" ,
html: `
<div class="container">
<div class="header">
<div class="logo">📱 WhatsApp Group Manager</div>
<h1 class="title">Reset Your Password</h1>
<p class="subtitle">We received a request to reset your password</p>
</div>
<div class="content">
<p>Click the button below to reset your password:</p>
<div style="text-align: center;">
<a href=" ${ url } " class="reset-button">Reset Your Password</a>
</div>
<div class="warning">
<strong>⚠️ Security Notice:</strong> This password reset link will
expire in 1 hour for your security.
</div>
</div>
</div>
` ,
};
const response = await mg . messages . create ( env . MAILGUN_DOMAIN , emailData );
return { success: true , messageId: response . id };
}
Password reset links expire after 1 hour for security. Users must request a new link if it expires.
3. Password Changed Confirmation
Sent after successful password change:
src/server/mailgun.ts:162
export async function sendPasswordChangedNotification ( email : string ) {
const emailData = {
from: env . FROM_EMAIL ,
to: email ,
subject: "Password Changed Successfully - WhatsApp Group Manager" ,
html: `
<div class="container">
<div class="header">
<div class="logo">📱 WhatsApp Group Manager</div>
<div class="success-icon">✅</div>
<h1 class="title">Password Changed Successfully</h1>
</div>
<div class="content">
<p>Your password has been successfully changed.</p>
<div class="info-box">
<strong>✓ Password Updated:</strong> Your account is now secured
with your new password.
</div>
<p><strong>Didn't make this change?</strong> Contact support immediately.</p>
</div>
</div>
` ,
};
const response = await mg . messages . create ( env . MAILGUN_DOMAIN , emailData );
return { success: true , messageId: response . id };
}
Dual-Channel Delivery System
The notification system attempts WhatsApp first, then falls back to email:
src/server/mailgun.ts:496
export async function notifyAdminOfNewRegistration ( userName : string , userEmail : string ) {
const results = {
whatsapp: false ,
email: false ,
errors: [] as string []
};
// Try WhatsApp first
try {
await sendWhatsAppNotificationToAdmin ( userName , userEmail );
results . whatsapp = true ;
console . log ( "WhatsApp notification sent successfully" );
} catch ( error ) {
console . log ( "WhatsApp notification failed, falling back to email:" , error );
results . errors . push ( `WhatsApp failed: ${ error . message } ` );
// Fallback to email
try {
await sendUserRegistrationNotificationToAdmin ( userName , userEmail );
results . email = true ;
console . log ( "Email notification sent successfully" );
} catch ( error ) {
console . error ( "Email notification also failed:" , error );
results . errors . push ( `Email failed: ${ error . message } ` );
}
}
if ( ! results . whatsapp && ! results . email ) {
throw new Error ( `Failed to send notifications: ${ results . errors . join ( ', ' ) } ` );
}
return results ;
}
WhatsApp Attempt
System tries to send via WhatsApp using admin’s active session
Email Fallback
If WhatsApp fails (session disconnected, API error, etc.), automatically send email
Error Handling
If both channels fail, throw error with detailed failure reasons
Success Response
Return status of both channels and any error messages
Notification API
The notification router exposes the dual-channel system:
src/server/api/routers/notification.ts:5
export const notificationRouter = createTRPCRouter ({
notifyAdminOfUserRegistration: publicProcedure
. input ( z . object ({
userName: z . string (),
userEmail: z . string (). email (),
}))
. mutation ( async ({ input }) => {
try {
const result = await notifyAdminOfNewRegistration (
input . userName ,
input . userEmail
);
return {
success: true ,
whatsappSent: result . whatsapp ,
emailSent: result . email ,
errors: result . errors ,
};
} catch ( error ) {
return {
success: false ,
whatsappSent: false ,
emailSent: false ,
errors: [ error . message ],
};
}
}),
});
Overall success status (true if at least one channel succeeded)
Whether WhatsApp notification was delivered
Whether email notification was delivered
Array of error messages if any channel failed
Email Template Features
All email notifications include:
Mobile-friendly layouts
Maximum width of 600px
Proper viewport meta tags
Consistent font sizes
Branded colors (WhatsApp green: #25D366)
Clean typography using system fonts
Consistent spacing and padding
Subtle shadows and borders
Clear expiration warnings
“Do not reply” disclaimers
Security tips and best practices
Suspicious activity warnings
Plain text alternatives
Semantic HTML structure
High contrast text
Clear call-to-action buttons
WhatsApp notifications use Markdown-style formatting:
🔔 *New User Registration*
A new user has registered for WhatsApp Group Manager:
👤 *Name:* John Doe
📧 *Email:* [email protected]
📅 *Date:* 3/4/2026
Please review and approve this registration in the admin dashboard.
https://your-app.com/admin
WhatsApp supports basic Markdown:
*bold* for bold text
_italic_ for italic text
Emojis for visual enhancement
Error Handling
WhatsApp Errors
Common WhatsApp notification failures:
No admin user found in database
No active WhatsApp session for admin
WAHA API unreachable
Invalid API key
Admin phone number misconfigured
Email Errors
Common email notification failures:
Invalid Mailgun API key
Unverified sending domain
Recipient email blocked
Rate limits exceeded
Invalid email format
Monitoring Notifications
Track notification delivery:
console . log ( "WhatsApp notification sent successfully:" , response );
console . log ( "Email notification sent successfully:" , response );
console . error ( "Failed to send notification:" , error );
Best Practices for Monitoring
Log all notification attempts
Track success/failure rates
Monitor Mailgun dashboard for email metrics
Set up alerts for consistent failures
Review error messages regularly
Configuration Checklist
Mailgun Setup
Create Mailgun account
Verify sending domain
Get API key
Set FROM_EMAIL on verified domain
Environment Variables
MAILGUN_API_KEY = key-xxx
MAILGUN_DOMAIN = mg.yourdomain.com
FROM_EMAIL = [email protected]
ADMIN_EMAIL = [email protected]
ADMIN_PHONE_NUMBER = 1234567890
BETTER_AUTH_URL = https://your-app.com
WAHA_API_URL = http://localhost:3000
WAHA_API_KEY = your-waha-key
WhatsApp Session
Admin must have active WhatsApp session
Session must be CONNECTED status
Verify session in admin dashboard
Test Notifications
Create test user registration
Verify WhatsApp delivery
Verify email fallback
Check error logging
Security Considerations
Use environment variables for sensitive data
Never expose API keys in client code
Verify Mailgun domain with SPF/DKIM
Use TLS for email transmission
Secure WAHA API with strong API key
Use HTTPS for API endpoints
Validate admin session before sending
Rate limit notification sends
Only send necessary user information
Don’t include passwords in notifications
Use secure links with proper authentication
Follow GDPR/privacy regulations
Customization
Customize notification templates:
Email Branding
WhatsApp Messages
Edit HTML templates in src/server/mailgun.ts:
Update logo and colors
Modify email copy
Add company branding
Customize button styles
Edit message templates in sendWhatsAppNotificationToAdmin:
Adjust message format
Change emoji usage
Modify link structure
Update greeting text
Next Steps
Admin Dashboard Learn about receiving and acting on notifications
Authentication Understand user registration flow