Skip to Content
Dirly 2.0 is released 🎉
Email Notifications

Email Notifications

Automated email system for approval and rejection notifications using Resend

Dirly uses Resend  to send automated email notifications to tool submitters when their submissions are reviewed.

Configuration

Email notifications require two environment variables:

.env.local

RESEND_API_KEY=re_your_api_key_here FROM_EMAIL=Dirly <noreply@yourdomain.com>

Get Resend API Key

Sign up at resend.com  and create an API key from your dashboard.

Configure Sender Email

Set FROM_EMAIL to use your verified domain. If not set, it defaults to Dirly <onboarding@resend.dev>.

Verify Domain (Production)

For production use, verify your domain in Resend to avoid emails being marked as spam.

If RESEND_API_KEY is not set, email sending will fail gracefully with a console warning, but the approval/rejection process will still complete.

Email Service Implementation

The core email service is in lib/email.ts:11-36:

export async function sendEmail(data: EmailData) { if (!process.env.RESEND_API_KEY) { console.warn('RESEND_API_KEY not set, email not sent'); return { success: false, error: 'RESEND_API_KEY not configured' }; } try { const result = await resend.emails.send({ from: process.env.FROM_EMAIL || 'Dirly <onboarding@resend.dev>', to: data.to, subject: data.subject, html: data.html, }); if (result.error) { console.error('Resend API Error:', result.error); return { success: false, error: result.error }; } console.log('Email sent successfully:', result.data?.id); return { success: true, data: result.data }; } catch (error) { console.error('Failed to send email:', error); return { success: false, error }; } }

Approval Emails

When a tool is approved, the submitter receives a celebratory email.

Email Template Defined in lib/email.ts:69-100:

export function approvalEmail(toolName: string, toolUrl: string) { return { subject: `🎉 Your Tool is Now Live - ${toolName}`, html: ` <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px;"> <h2 style="color: #22c55e; border-bottom: 2px solid #22c55e; padding-bottom: 10px;"> Congratulations! Your tool has been approved! </h2> <p style="color: #666; line-height: 1.6;"> Great news! <strong>${toolName}</strong> has been approved and is now live on Dirly. </p> <div style="text-align: center; margin: 30px 0;"> <a href="${toolUrl}" style="background: #6366f1; color: white; padding: 12px 30px; text-decoration: none; border-radius: 6px; display: inline-block;"> View Your Tool </a> </div> <p style="color: #666; line-height: 1.6;"> Share your tool with the community and start collecting upvotes. The more engagement your tool receives, the higher it will rank in our directory. </p> <div style="margin-top: 30px; padding: 15px; background: #f0fdf4; border-radius: 8px; border-left: 4px solid #22c55e;"> <p style="color: #166534; margin: 0; font-size: 14px;"> <strong>Tip:</strong> Share your tool on social media to get more visibility and upvotes! </p> </div> </div> ` }; }

Approval Email Contents

  • Subject: 🎉 Your Tool is Now Live - {Tool Name}
  • Green success header with congratulations message
  • **Prominent CTA button **linking to the live tool page
  • Engagement tips to encourage sharing
  • Tip callout with green styling suggesting social media promotion

Sending Approval Emails

Emails are sent from app/admin/tools/[id]/page.tsx:38-54 after successful approval:

await approveTool({ toolId }); // Send approval email try { await fetch('/api/send-email', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ type: 'approval', recipientUserId: tool.submittedBy, preferenceKey: 'reviewStatusUpdates', data: { toolName: tool.name, toolUrl: `${window.location.origin}/tools/${tool.slug}` } }), }); } catch (emailError) { console.error('Failed to send approval email:', emailError); }

Rejection Emails

When a tool is rejected, the submitter receives feedback on why.

Email Template

Defined in lib/email.ts:102-128:

export function rejectionEmail(toolName: string, reason: string) { return { subject: `Tool Submission Update - ${toolName}`, html: ` <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px;"> <h2 style="color: #ef4444; border-bottom: 2px solid #ef4444; padding-bottom: 10px;"> Tool Submission Update </h2> <p style="color: #666; line-height: 1.6;"> Thank you for submitting <strong>${toolName}</strong> to Dirly. After review, we were unable to approve your submission at this time. </p> <div style="margin: 20px 0; padding: 15px; background: #fef2f2; border-radius: 8px; border-left: 4px solid #ef4444;"> <p style="color: #991b1b; margin: 0; font-size: 14px;"> <strong>Reason:</strong><br> ${reason} </p> </div> <p style="color: #666; line-height: 1.6;"> You're welcome to resubmit after addressing the feedback above. If you have any questions, feel free to reach out to our support team. </p> </div> ` }; }

Rejection Email Contents

  • Subject: Tool Submission Update - {Tool Name}
  • Red header indicating rejection
  • Polite rejection message thanking them for submitting
  • Prominent reason callout with red styling showing admin feedback
  • Invitation to resubmit after addressing issues
  • Support contact offer for questions

Sending Rejection Emails

Emails are sent from app/admin/tools/[id]/page.tsx:73-90 after rejection:

await rejectTool({ toolId }); // Send rejection email try { await fetch('/api/send-email', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ type: 'rejection', recipientUserId: tool.submittedBy, preferenceKey: 'reviewStatusUpdates', data: { toolName: tool.name, reason: rejectReason.trim() } }), }); } catch (emailError) { console.error('Failed to send rejection email:', emailError); }

Other Email Templates

The email library also includes templates for:

Submission Confirmation

lib/email.ts:39-67 - Sent when a user submits a new tool:

export function submissionConfirmationEmail(toolName: string)
  • Confirms receipt of submission
  • Explains the review process (1-3 business days)
  • Sets expectations for what happens next

Admin Notifications

lib/email.ts:130-157 - Notifies admins of new submissions:

export function adminNotificationEmail(toolName: string, submittedBy: string, adminUrl: string)
  • Alerts admins to pending reviews
  • Includes tool name and submitter
  • Contains direct link to admin review page
All email templates use inline CSS styling for maximum email client compatibility.

Error Handling

Email failures are logged but don’t block the approval/rejection process:

try { await fetch('/api/send-email', { /* ... */ }); } catch (emailError) { console.error('Failed to send approval email:', emailError); // Process continues even if email fails }

This ensures that:

  • Tool status updates always complete
  • Email issues don’t break the admin workflow
  • Errors are logged for debugging
  • Users aren’t left in limbo if emails fail
Last updated on