diff --git a/docs/docs/scheduled-triggers/recipes/daily-summary-email.mdx b/docs/docs/scheduled-triggers/recipes/daily-summary-email.mdx
index 40f1edcb502..8f699a27293 100644
--- a/docs/docs/scheduled-triggers/recipes/daily-summary-email.mdx
+++ b/docs/docs/scheduled-triggers/recipes/daily-summary-email.mdx
@@ -16,6 +16,7 @@ sidebar_position: 2
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import Thumbnail from '@site/src/components/Thumbnail';
+import SampleAppBlock from '@site/src/components/SampleAppBlock';
# Send a Daily Summary Email
@@ -26,19 +27,25 @@ guide, we'll explore how to use Scheduled Triggers to send each user a daily sum
have received. We'll do this by executing this trigger every morning and seeing what new notifications have come through
in the last twenty-four hours. If a user has new notifications, they'll get an email listing them all.
+
+
## Prerequisites
Before getting started, ensure that you have the following in place:
-- A Hasura project, either locally or using [Hasura Cloud](https://cloud.hasura.io/?skip_onboarding=true).
+- The docs e-commerce sample app deployed to Hasura Cloud.
- A working SMTP server or email-sending service that you can integrate with to send emails.
-- If you plan on using a webhook endpoint hosted on your own machine with a Hasura project hosted elsewhere, ensure that
- you have a tunneling service such as [ngrok](https://ngrok.com/) set up so that a remotely hosted instance can
- communicate with your local machine.
+
+:::info Tunneling your webhook endpoint from your local machine
+
+If you plan on using a webhook endpoint hosted on your own machine, ensure that you have a tunneling service such as
+[ngrok](https://ngrok.com/) set up so that your Cloud Project can communicate with your local machine.
+
+:::
## Our model
-When sending transactionary emails such as this, there are three fundamental components to consider:
+When sending transactional emails such as this, there are three fundamental components to consider:
- **Your data source**: In your database, which table contains the value that you want to use to determine whether or
not to send the email?
@@ -46,54 +53,14 @@ When sending transactionary emails such as this, there are three fundamental com
email? How will you return information so that you have the correct data to include in the email?
- **Your email templating**: How will you generate and send the email containing the information you want to send?
-For simplicity, we're assuming there are two tables in our database: `users` and `notifications`. The `users` table
-contains the details of all users, including the user's email address. The `notifications` table contains all
-notifications sent to users. Each notification has a `user_id` property that references the user to whom the
-notification was sent.
-
-
-
-Click here for the SQL to generate these tables and some seed data.
-
-
-```sql
--- create the users table
-CREATE TABLE public.users (
- id uuid PRIMARY KEY,
- email varchar(255) NOT NULL,
- name varchar(100) NOT NULL
-);
-
--- create the notifications table
-CREATE TABLE public.notifications (
- id serial PRIMARY KEY,
- user_id uuid NOT NULL REFERENCES public.users(id),
- message text NOT NULL,
- created_at timestamp DEFAULT now()
-);
-
--- seed data for the users table
-INSERT INTO public.users (id, email, name) VALUES
- ('6f809f39-07a1-4c3b-a5e5-8e6d905366f1', 'user1@example.com', 'Daniel Ricciardo'),
- ('d0f29c98-c789-4ec0-b84c-1593a6a8d0c2', 'user2@example.com', 'Charles Leclerc'),
- ('acde545e-32d3-4f28-9475-61ab26a555d9', 'user3@example.com', 'Carlos Sainz');
-
--- seed data for the notifications table
-INSERT INTO public.notifications (user_id, message, created_at) VALUES
- ('6f809f39-07a1-4c3b-a5e5-8e6d905366f1', 'Your order has been shipped!', NOW() - INTERVAL '30 hours'),
- ('d0f29c98-c789-4ec0-b84c-1593a6a8d0c2', 'New product added: Smartphone XYZ is now available!', NOW() - INTERVAL '30 hours'),
- ('acde545e-32d3-4f28-9475-61ab26a555d9', 'Special offer: Get 20% off on all electronics!', NOW() - INTERVAL '30 hours');
-```
-
-You can copy / paste this into the `RUN SQL` tab in the Hasura Console on the `Data` page. Then, track all relationships
-under the `Public` schema on the `Data` page.
-
-
+Our sample app's database contains, among others, two tables: `users` and `notifications`. The `users` table contains
+the details of all users, including the user's email address. The `notifications` table contains all notifications sent
+to users. Each notification has a `user_id` property that references the user to whom the notification was sent.
## Step 1: Create the Scheduled Event
-Head to your the Hasura Console of your project and navigate to the "Events" tab. From there, click on the
-`Cron Triggers` item in the sidebar. Then, click `Create`:
+Head to the Hasura Console of your project and navigate to the "Events" tab. From there, click on the `Cron Triggers`
+item in the sidebar. Then, click `Create`:
/daily-summary
```
:::info Tunneling your webhook endpoint
-If you're not running your Hasura instance on the same machine as your webhook endpoint, you'll need to use a tunneling
-service such as [ngrok](https://ngrok.com/) to expose your webhook endpoint to the internet. This will allow you to
-expose a public URL that will forward requests to your local machine and the server we'll configure below.
+Since our project is running on Hasura Cloud, and our handler will run on our local machine, we'll use ngrok to expose
+the webhook endpoint to the internet. This will allow us to expose a public URL that will forward requests to our local
+machine and the server we'll configure below.
You'll need to modify your webhook URL to use the public URL provided by ngrok.
+After installing ngrok and
+[authenticating](https://ngrok.com/docs/secure-tunnels/ngrok-agent/tunnel-authtokens/#:~:text=Once%20you've%20signed%20up,make%20installing%20the%20authtoken%20simple.),
+you can do this by running:
+
+```bash
+ngrok http 4000
+```
+
+Then, copy the `Forwarding` value for use in our webhook 🎉
+
:::
Next, we'll configure the cron expression that will trigger the event. In this example, we want to send requests at 9:00
@@ -205,7 +182,7 @@ nodemailer.createTestAccount((err, account) => {
});
// Our route for the webhook
- app.post('/review-request', async (req, res) => {
+ app.post('/daily-summary', async (req, res) => {
// confirm the auth header is correct — ideally, you'd keep the secret in an environment variable
const authHeader = req.headers['secret-authorization-string'];
if (authHeader !== 'super_secret_string_123') {
@@ -217,29 +194,29 @@ nodemailer.createTestAccount((err, account) => {
// get our date ready for the query
const today = new Date();
const twentyFourHoursPrior = new Date(today.setDate(today.getDate() - 1));
- const twentyFourHoursPriorAsTimestamp = twentyFourHoursPrior.toISOString().split('T')[0];
+ const twentyFourHoursPriorAsTimestamp = twentyFourHoursPrior.toISOString();
// Fetch the data from our Hasura instance
async function getRecentNotifications() {
- const response = await fetch('http://localhost:8080/v1/graphql', {
+ const response = await fetch('', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
- // "x-hasura-admin-secret": "",
+ 'x-hasura-admin-secret': '',
},
body: JSON.stringify({
query: `
- query DailyNotificationsQuery($start_time: timestamp!) {
- users {
+ query DailyNotificationsQuery($start_time: timestamptz!) {
+ notifications(where: {created_at: {_gte: $start_time}}) {
+ id
+ message
+ user {
id
email
name
- notifications(where: {created_at: {_gte: $start_time}}) {
- id
- message
- }
- }
+ }
}
+ }
`,
variables: {
start_time: twentyFourHoursPriorAsTimestamp,
@@ -247,41 +224,31 @@ nodemailer.createTestAccount((err, account) => {
}),
});
const { data } = await response.json();
- return data.users;
+ return data.notifications;
}
// get our users and filter out the ones with no notifications
- let users = await getRecentNotifications();
- users = users.filter(user => user.notifications.length > 0);
-
- // helper function to list the notifications in the email
- function listNotifications(notifications) {
- let list = '';
- notifications.map(notification => {
- list += `- ${notification.message}\n`;
- });
- return list;
- }
+ let notifications = await getRecentNotifications();
// map over the data and send an email to each user
- async function sendReviewRequests() {
+ async function sendNotificationSummary(notifications) {
let outcomes = [];
- users.map(async user => {
+ notifications.map(async notification => {
// Create a message object
const message = {
from: 'SuperStore.com ',
- to: `${user.name} <${user.email}>`,
- subject: `You've got new notifications, ${user.name.split(' ')[0]}!`,
- text: `Hi ${user.name.split(' ')[0]},\n\nCheck out your recent notifications:\n\n${listNotifications(
- user.notifications
- )}`,
+ to: `${notification.user.name} <${notification.user.email}>`,
+ subject: `You've got new notifications, ${notification.user.name.split(' ')[0]}!`,
+ text: `Hi ${notification.user.name.split(' ')[0]},\n\nCheck out your recent notifications:\n\n${
+ notification.message
+ }\n\nThanks,\nSuperStore.com`,
};
// Send the message using the Nodemailer transporter
const info = await transporter.sendMail(message);
// Log the message info
- console.log(`\nMessage sent to ${user.name}: ${nodemailer.getTestMessageUrl(info)}`);
+ console.log(`\nMessage sent to ${notification.user.name}: ${nodemailer.getTestMessageUrl(info)}`);
// add the info to the outcomes array
outcomes.push({
@@ -292,11 +259,11 @@ nodemailer.createTestAccount((err, account) => {
});
}
- await sendReviewRequests(users);
+ await sendNotificationSummary(notifications);
// Return a JSON response to the client
res.json({
- message: 'Review requests sent!',
+ message: 'Notifications sent!',
});
});