Mail in response to events
Building a Secure Webhook with Bearer Authentication in ExpressJS and Sending HTML Emails with Mailchain SDK Using Ngrok and Pagoda Alerts. In this tutorial, you will create a secure webhook with Bearer authentication in an ExpressJS app and send an HTML mail with the Mailchain SDK. This webhook will listen for incoming requests, validate the Bearer token, and send an mail containing the webhook data as an HTML mail. We will use Ngrok to expose the local server and Pagoda Alerts to trigger the webhook upon specific events.
Ngrok
Ngrok will be used to expose your local machine to the internet in order to be accessible remotely for example by a webhook.
Setup
Sign up for an Ngrok account account, its free. Follow Ngrok's getting started guide to install and setup Ngrok on your machine.
Running Ngrok
To run Ngrok, open a terminal and run the following command:
ngrok http 3000
Once it's running successfully the output should be similar to below.
Session Status online
Session Expires 1 hour, 59 minutes
Terms of Service https://ngrok.com/tos
Version 3.2.2
Region Europe (eu)
Latency -
Web Interface http://127.0.0.1:4040
Forwarding https://xxxx-xx-xx-xxx-xxx.eu.ngrok.io -> http://localhost:3000
Connections ttl opn rt1 rt5 p50 p90
0 0 0.00 0.00 0.00 0.00
Don't stop ngrok
or close this terminal window, you need Ngrok running to accept connections.
The output contains some important information that you will use later so make note of it.
- Web Interface - http://127.0.0.1:4040 this is helpful for debugging and monitoring your tunnel.
- Forwarding - The first url which will be similar but different to
https://xxxx-xx-xx-xxx-xxx.eu.ngrok.io
is the publicly accessible URL. The second url which will contain the port number you used when starting ngrokhttp://localhost:3000
is where it will forward traffic to.
Pagoda
Create an account
To get started, you will need to create a Pagoda account. You can do this by going to console.pagoda.co and clicking on the “Sign Up” button. You will be prompted to enter your mail address and create a password. Once you have created your account, you will be redirected to the Pagoda console.
Configure Pagoda Alerts
In this step, we will configure a webhook trigger using Pagoda Alerts to call our webhook when an event of interest occurs. We will use the public URL generated by ngrok in Step 1. Follow these steps to set up an alert using Pagoda Alerts:
- Go to console.pagoda.co.
- Create a new project, selecting a Blank project, then add a project name, e.g.
mailchain-events
. - Select your project and head to the “Alerts” section.
- Ensure
Testnet
is selected in the navigation bar. - Click on
+ New Alert
and configure the alert settings:- For the testnet target, enter your NEAR testnet account. This could also be a contract.
- Select the condition (e.g.,
Successful Action
). - Under destination, select
webhooks
.
- Add the webhook URL obtained from Ngrok with an endpoint that we will add later (e.g.,
webhook
). Use the ngrok HTTPS URL from Step 1 as the webhook URL. It should look something like:https://xxxx-xx-xx-xxx-xxx.ngrok-free.app/webhook
- Click
Create
. - Copy the Bearer token in the next step and then click finish.
- Remember to click the
+ Create Alert
button on the main alerts page.
Create the ExpressJS App
Make sure you have configured your application and authenticated the Mailchain SDK.
Configure Pagoda
Open the the .env
file, you should already see a value for SECRET_RECOVERY_PHRASE
. Below it add your bearer token from Pagoda.
You bearer token is a secret and should not be shared with anyone. You can get it from the destination tab in the alerts section of the Pagoda console.
SECRET_RECOVERY_PHRASE=your_secret_recovery_phrase
BEARER_TOKEN=your_bearer_token
Install dependencies
You will use the following dependencies:
express
- a web framework for NodeJS.passport
- authentication middleware for NodeJS.passport-http-bearer
- Bearer authentication strategy for Passport.dotenv
- loads environment variables from a.env
file intoprocess.env
.@mailchain/sdk
- Mailchain SDK for web3 communication.
Install the required dependencies by running:
- npm
- Yarn
- pnpm
npm install express passport passport-http-bearer dotenv @mailchain/sdk
yarn add express passport passport-http-bearer dotenv @mailchain/sdk
pnpm add express passport passport-http-bearer dotenv @mailchain/sdk
Creating the ExpressJS App
Create pagodaWebhookServer.js
and paste the following code.
const { Mailchain } = require('@mailchain/sdk');
const express = require('express');
const passport = require('passport');
const BearerStrategy = require('passport-http-bearer').Strategy;
const dotenv = require('dotenv');
// setup dotenv to read .env vars into Node
dotenv.config();
const app = express();
app.use(express.json());
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
// setup passport
app.use(passport.initialize());
passport.use(
new BearerStrategy((token, done) => {
if (token === process.env.BEARER_TOKEN) {
return done(null, true);
}
return done(null, false);
}),
);
// create a new instance of the Mailchain SDK with the secret recovery phrase
const mailchain = Mailchain.fromSecretRecoveryPhrase(process.env.SECRET_RECOVERY_PHRASE);
app.post('/webhook', passport.authenticate('bearer', { session: false }), async (req, res) => {
const formattedPayload = JSON.stringify(req.body, null, 2);
const user = await mailchain.user();
const { data: sentMail, error: sentMailError } = await mailchain.sendMail({
from: user.address,
to: [user.address],
subject: 'New transaction received via Pagoda Webhook',
content: {
text: `The webhook body:\n${formattedPayload}`,
html: `<p>The webhook body:</p><pre>${formattedPayload}</pre>`,
},
});
if (sentMailError) {
res.status(500).json({ message: 'Internal server error', sentMailError });
console.error('Mail failed to send:', sentMailError);
}
res.status(200).json({ message: 'Mail sent successfully', sentMail });
console.log('Mail sent successfully', sentMail);
});
This code does the following:
- Creates an ExpressJS app that listens to
POST
requests on the/webhook
endpoint. - Uses the bearer strategy from
passport-http-bearer
to authenticate requests. - Authenticates the SDK and gets current user's address.
- Set
from
andto
address to the authenticated user. - Set
subject
andbody
of the mail. - Sends mail.
In your terminal window run node pagodaWebhookServer.js
to run your Express server. You should see a message in your terminal window that looks similar to below. Your ExpressJS app is now ready to receive webhook requests with Bearer authentication and send an HTML mail using the Mailchain SDK. When the selected event occurs, Pagoda Alerts will call your webhook, which in turn will authenticate the Bearer token and send an HTML mail using the Mailchain SDK.
Server running on port 3000.
Send a transaction to the address configured in the Pagoda dashboard to see the webhook in action!
Your application is now running and ready to receive requests.
Send a transaction
To test it, you can send a transaction to the address configured in the Pagoda dashboard. You can do this by using the NEAR Wallet or the NEAR CLI. Once you have sent a transaction, you should receive a mail with the transaction details.
You configured Pagoda to use the testnet, so you will need to use a testnet account. You can create a testnet account using the testnet NEAR Wallet.
Once you have created a testnet account, you can send a transaction to the address configured in the Pagoda dashboard. After you have sent a transaction, Pagoda will sent a POST request to your Express JS app, check your console window for output.
After it has been successfully sent check your inbox and you will have a mail with the transaction details.
Conclusion
In conclusion, we have demonstrated how to create an ExpressJS app that provides a secure webhook endpoint with Bearer authentication using PassportJS. We also showed how to send HTML mails using the Mailchain SDK when the webhook is called. To make the webhook accessible over the internet, we used ngrok to expose the local server with a public URL. Finally, we configured Pagoda Alerts to trigger the webhook upon specific events. This setup enables you to receive incoming webhook data securely, notify recipients with the webhook data through mail, and react to events in real-time using Pagoda Alerts. You can now use this knowledge to enhance your applications, improve the way you handle webhooks and mail notifications, and integrate various services using Pagoda Alerts to create powerful and versatile workflows.
Troubleshooting
There are a few things you can check if you are having trouble getting the webhook to work.
I didn't get an event notification
Things to check:
- Check if the ExpressJS app received the request. Make sure your application is running and look the console window where you ran the ExpressJS app. You should see some logs each time an event is received.
- Check if Ngrok received the request. Make sure that Ngrok is running and navigate to the Ngrok console here you can see the HTTP requests sent to your endpoint.
- Check the webhook address is correct. Navigate to the destination tab in the Pagoda console and check the webhook address is correct. You can find the webhook address from the ngrok console. Remember to make sure you've added
/webhook
to the end of the ngrok URL. - Check Pagoda has received the event. Navigate to the activity tab in the Pagoda console and check the events have been received.
You can skip Pagoda and send a mock event to your webhook. You can use the following curl command to send a mock event to your webhook.
curl -X POST **INSERT_NGROK_URL**/webhook \
--header 'Content-Type: application/json; charset=utf-8' \
--header 'Authorization: Bearer **INSERT_BEARER_TOKEN**' \
--data @- << EOF
{
"chain_id": "Testnet",
"alert_rule_id": 297,
"alert_name": "Successful action in mailchain-alice.testnet",
"payload": {
"Actions": {
"block_hash": "7NBM1FDCqraLkunrYRLozEWhNXKhD64MRVccxDe5HfJY",
"receipt_id": "FFBCePYYMmqaroZeRPGejssTw6dxsTuksgkGwrB3bydc",
"transaction_hash": "5eCqaKQ3XSVWWfcKV5wzh46FenHp6YgqsRWnYJbvSDic"
}
}
}
EOF
Remember to set the BEARER_TOKEN to your bearer token in your .env
file.