This workflow follows the Emailsend → Postgres recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "EduPrime - Daily Management Report",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 24,
"triggerAtHour": 18
}
]
}
},
"id": "schedule-trigger",
"name": "Daily 6 PM Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.1,
"position": [
250,
300
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "-- Today's attendance summary\nWITH today_attendance AS (\n SELECT \n COUNT(DISTINCT student_id) as total_marked,\n COUNT(CASE WHEN status = 'present' THEN 1 END) as present_count,\n COUNT(CASE WHEN status = 'absent' THEN 1 END) as absent_count,\n COUNT(CASE WHEN status = 'late' THEN 1 END) as late_count\n FROM attendance\n WHERE date = CURRENT_DATE\n),\n-- Today's fee collection\nfee_collection AS (\n SELECT \n COUNT(*) as payments_count,\n COALESCE(SUM(amount), 0) as total_collected\n FROM fees\n WHERE payment_date = CURRENT_DATE AND status = 'paid'\n),\n-- Pending fees summary\npending_fees AS (\n SELECT \n COUNT(*) as pending_count,\n COALESCE(SUM(amount), 0) as pending_amount,\n COUNT(CASE WHEN due_date < CURRENT_DATE THEN 1 END) as overdue_count,\n COALESCE(SUM(CASE WHEN due_date < CURRENT_DATE THEN amount END), 0) as overdue_amount\n FROM fees\n WHERE status IN ('pending', 'overdue')\n),\n-- New inquiries today\nnew_inquiries AS (\n SELECT COUNT(*) as count\n FROM inquiries\n WHERE DATE(created_at) = CURRENT_DATE\n),\n-- Low attendance students (below 75%)\nlow_attendance AS (\n SELECT COUNT(DISTINCT s.id) as count\n FROM students s\n JOIN attendance a ON s.id = a.student_id\n WHERE a.date >= CURRENT_DATE - INTERVAL '30 days'\n GROUP BY s.id\n HAVING COUNT(CASE WHEN a.status = 'present' THEN 1 END) * 100.0 / COUNT(*) < 75\n)\nSELECT \n ta.*,\n fc.*,\n pf.*,\n ni.count as new_inquiries,\n la.count as low_attendance_students\nFROM today_attendance ta\nCROSS JOIN fee_collection fc\nCROSS JOIN pending_fees pf\nCROSS JOIN new_inquiries ni\nCROSS JOIN low_attendance la",
"additionalFields": {}
},
"id": "get-daily-stats",
"name": "Get Daily Statistics",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.3,
"position": [
450,
300
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "executeQuery",
"query": "SELECT \n b.name as batch_name,\n COUNT(CASE WHEN a.status = 'present' THEN 1 END) as present,\n COUNT(CASE WHEN a.status = 'absent' THEN 1 END) as absent,\n ROUND(COUNT(CASE WHEN a.status = 'present' THEN 1 END) * 100.0 / NULLIF(COUNT(*), 0), 1) as attendance_rate\nFROM batches b\nJOIN attendance a ON b.id = a.batch_id\nWHERE a.date = CURRENT_DATE\nGROUP BY b.name\nORDER BY attendance_rate DESC",
"additionalFields": {}
},
"id": "get-batch-attendance",
"name": "Get Batch Attendance",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.3,
"position": [
450,
500
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"mode": "runOnceForAllItems",
"jsCode": "const stats = $('Get Daily Statistics').first().json;\nconst batchAttendance = $('Get Batch Attendance').all().map(i => i.json);\n\nconst today = new Date().toLocaleDateString('en-IN', {\n weekday: 'long',\n year: 'numeric',\n month: 'long',\n day: 'numeric'\n});\n\nconst attendanceRate = stats.total_marked > 0 \n ? ((stats.present_count / stats.total_marked) * 100).toFixed(1) \n : 0;\n\nlet batchSummary = batchAttendance.map(b => \n `\u2022 ${b.batch_name}: ${b.present}/${b.present + b.absent} (${b.attendance_rate}%)`\n).join('\\n');\n\nif (!batchSummary) batchSummary = '\u2022 No attendance data available';\n\nconst report = `\ud83d\udcca *EduPrime Daily Report*\n\ud83d\udcc5 ${today}\n\n*\u2501\u2501\u2501 \ud83d\udccb ATTENDANCE SUMMARY \u2501\u2501\u2501*\n\u2705 Present: ${stats.present_count}\n\u274c Absent: ${stats.absent_count}\n\u23f0 Late: ${stats.late_count}\n\ud83d\udcc8 Rate: ${attendanceRate}%\n\n*Batch-wise Attendance:*\n${batchSummary}\n\n*\u2501\u2501\u2501 \ud83d\udcb0 FEE COLLECTION \u2501\u2501\u2501*\n\ud83d\udcb5 Today's Collection: \u20b9${Number(stats.total_collected).toLocaleString('en-IN')}\n\ud83d\udcdd Payments: ${stats.payments_count}\n\n*Pending Summary:*\n\u23f3 Pending: \u20b9${Number(stats.pending_amount).toLocaleString('en-IN')} (${stats.pending_count} students)\n\ud83d\udea8 Overdue: \u20b9${Number(stats.overdue_amount).toLocaleString('en-IN')} (${stats.overdue_count} students)\n\n*\u2501\u2501\u2501 \ud83d\udcde INQUIRIES \u2501\u2501\u2501*\n\ud83c\udd95 New Today: ${stats.new_inquiries}\n\n*\u2501\u2501\u2501 \u26a0\ufe0f ALERTS \u2501\u2501\u2501*\n\ud83d\udcc9 Low Attendance Students: ${stats.low_attendance_students}\n\n_Report generated automatically by EduPrime_`;\n\nreturn [{\n json: {\n report,\n stats,\n batchAttendance\n }\n}];"
},
"id": "generate-report",
"name": "Generate Report",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
700,
400
]
},
{
"parameters": {
"resource": "message",
"operation": "send",
"phoneNumberId": "={{ $env.WHATSAPP_PHONE_NUMBER_ID }}",
"recipientPhoneNumber": "={{ $env.ADMIN_WHATSAPP }}",
"textBody": "={{ $json.report }}"
},
"id": "send-whatsapp-admin",
"name": "Send to Admin (WhatsApp)",
"type": "n8n-nodes-base.whatsApp",
"typeVersion": 1,
"position": [
950,
300
],
"credentials": {
"whatsAppApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"channel": "#daily-reports",
"text": "={{ $json.report }}",
"otherOptions": {}
},
"id": "send-slack",
"name": "Send to Slack",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.1,
"position": [
950,
500
],
"credentials": {
"slackApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"fromEmail": "={{ $env.SMTP_FROM_EMAIL }}",
"toEmail": "={{ $env.ADMIN_EMAIL }}",
"subject": "=EduPrime Daily Report - {{ new Date().toLocaleDateString('en-IN') }}",
"emailType": "html",
"html": "<!DOCTYPE html>\n<html>\n<head>\n <style>\n body { font-family: Arial, sans-serif; }\n .header { background: #4e73df; color: white; padding: 20px; }\n .section { margin: 20px 0; padding: 15px; background: #f8f9fc; border-radius: 8px; }\n .stat { display: inline-block; margin: 10px; padding: 15px; background: white; border-radius: 8px; text-align: center; }\n .stat h3 { margin: 0; color: #4e73df; }\n .stat p { margin: 5px 0 0; color: #666; }\n table { width: 100%; border-collapse: collapse; }\n th, td { padding: 10px; text-align: left; border-bottom: 1px solid #ddd; }\n th { background: #4e73df; color: white; }\n </style>\n</head>\n<body>\n <div class=\"header\">\n <h1>\ud83d\udcca EduPrime Daily Report</h1>\n <p>{{ new Date().toLocaleDateString('en-IN', {weekday: 'long', year: 'numeric', month: 'long', day: 'numeric'}) }}</p>\n </div>\n \n <div class=\"section\">\n <h2>\ud83d\udccb Attendance Summary</h2>\n <div class=\"stat\"><h3>{{ $json.stats.present_count }}</h3><p>Present</p></div>\n <div class=\"stat\"><h3>{{ $json.stats.absent_count }}</h3><p>Absent</p></div>\n <div class=\"stat\"><h3>{{ $json.stats.late_count }}</h3><p>Late</p></div>\n </div>\n \n <div class=\"section\">\n <h2>\ud83d\udcb0 Fee Collection</h2>\n <div class=\"stat\"><h3>\u20b9{{ Number($json.stats.total_collected).toLocaleString('en-IN') }}</h3><p>Today's Collection</p></div>\n <div class=\"stat\"><h3>\u20b9{{ Number($json.stats.pending_amount).toLocaleString('en-IN') }}</h3><p>Pending</p></div>\n <div class=\"stat\"><h3>\u20b9{{ Number($json.stats.overdue_amount).toLocaleString('en-IN') }}</h3><p>Overdue</p></div>\n </div>\n \n <div class=\"section\">\n <h2>\ud83d\udcde Inquiries</h2>\n <div class=\"stat\"><h3>{{ $json.stats.new_inquiries }}</h3><p>New Today</p></div>\n </div>\n \n <p style=\"text-align: center; color: #666; margin-top: 30px;\">This report was generated automatically by EduPrime Management System</p>\n</body>\n</html>"
},
"id": "send-email-admin",
"name": "Send Email to Admin",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2.1,
"position": [
950,
700
],
"credentials": {
"smtp": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "executeQuery",
"query": "INSERT INTO reports (report_type, report_date, data, generated_at)\nVALUES (\n 'daily_summary',\n CURRENT_DATE,\n '={{ JSON.stringify($json) }}',\n NOW()\n)",
"additionalFields": {}
},
"id": "save-report",
"name": "Save Report to DB",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.3,
"position": [
1200,
400
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
}
],
"connections": {
"Daily 6 PM Trigger": {
"main": [
[
{
"node": "Get Daily Statistics",
"type": "main",
"index": 0
},
{
"node": "Get Batch Attendance",
"type": "main",
"index": 0
}
]
]
},
"Get Daily Statistics": {
"main": [
[
{
"node": "Generate Report",
"type": "main",
"index": 0
}
]
]
},
"Get Batch Attendance": {
"main": [
[
{
"node": "Generate Report",
"type": "main",
"index": 0
}
]
]
},
"Generate Report": {
"main": [
[
{
"node": "Send to Admin (WhatsApp)",
"type": "main",
"index": 0
},
{
"node": "Send to Slack",
"type": "main",
"index": 0
},
{
"node": "Send Email to Admin",
"type": "main",
"index": 0
}
]
]
},
"Send to Admin (WhatsApp)": {
"main": [
[
{
"node": "Save Report to DB",
"type": "main",
"index": 0
}
]
]
},
"Send to Slack": {
"main": [
[
{
"node": "Save Report to DB",
"type": "main",
"index": 0
}
]
]
},
"Send Email to Admin": {
"main": [
[
{
"node": "Save Report to DB",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"tags": [
"automation",
"reports",
"management"
]
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
postgresslackApismtpwhatsAppApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
EduPrime - Daily Management Report. Uses postgres, whatsApp, slack, emailSend. Scheduled trigger; 8 nodes.
Source: https://github.com/ayushee2290-crypto/EduPrime/blob/9d36c77934232f166afc4f5dd9b147c5d1f7f009/n8n-workflows/daily-report.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
EduPrime - Inquiry Follow-up Automation. Uses postgres, whatsApp, emailSend, slack. Webhook trigger; 8 nodes.
This workflow automates end-to-end research analysis by coordinating multiple AI models—including NVIDIA NIM (Llama), OpenAI GPT-4, and Claude to analyze uploaded documents, extract insights, and gene
This n8n workflow automates task creation and scheduled reminders for users via a Telegram bot, ensuring timely notifications across multiple channels like email and Slack. It streamlines task managem
🌸 Affirmation Sender + Weekly Gratitude Digest v2
This workflow contains community nodes that are only compatible with the self-hosted version of n8n.