Creating a Self-Destruct Email Message: A Guide
Image created by the author & Adobe FireFly

Creating a Self-Destruct Email Message: A Guide

Let's take an enchanting journey through time and space, where old school cartoons meet cutting-edge tech. You'll recall that ever-so-eager inspector with his gadget-filled hat, right? The charming Inspector Gadget. His mission briefings came in self-destructing messages. How about we try and craft one such adventure in the real-world? Drum rolls, please!


No alt text provided for this image
Inspector Gadget reading a self-destruct message


Here's what we'll need to start our fun-filled escapade:

  1. Node.js (our back-end engine)
  2. SQLite (our database savior)
  3. Nodemailer (our email express)
  4. AMP for Email (our secret sauce for dynamic emails)
  5. React (our front-end magician)

No worries if you're a greenhorn or a seasoned developer, this guide will be a rewarding endeavor for all. Buckle up, let's get started!

No alt text provided for this image
Diagram Flow of the Intended Solution


Setting Up Our Node.js Server

Start by installing Node.js and SQLite, if you haven't done so already. Once done, create a new Node.js project:


mkdir self-destruct-email && cd self-destruct-email
npm init -y        

Our trusty server will need the following packages: express, nodemailer, sqlite, sqlite3, and cors. Install them using npm:

npm install express nodemailer sqlite sqlite3 cors        


In the project root, create an index.js file and add the following code:

const express = require('express');
const nodemailer = require('nodemailer');
const cors = require('cors');
const { open } = require('sqlite');
const sqlite3 = require('sqlite3');

const app = express();
app.use(express.json());
app.use(cors());

let db;

(async () => {
? db = await open({
? ? filename: './emails.db',
? ? driver: sqlite3.Database
? });
? await db.exec('CREATE TABLE IF NOT EXISTS emails (id TEXT PRIMARY KEY, openedAt TEXT)');
})();


app.post('/send-email', async (req, res) => {
? let transporter = nodemailer.createTransport({
? ? service: 'gmail',
? ? auth: {
? ? ? user: '[email protected]',
? ? ? pass: 'yourpassword'
? ? }
? });

  // Replace the placeholder text with the user's message
? const ampMarkupWithMessage = req.body.message.replace('Confidential message goes here', req.body.message);
? 
  let info = await transporter.sendMail({
? ? from: '"Fun Times ??" <[email protected]>',
? ? to: req.body.email,
? ? subject: "Self Destruct in 5 Minutes ?",
    html: req.body.message,
? ? amp: req.body.message
? });


? res.json({ messageId: info.messageId });
});


app.get('/email-opened/:id', async (req, res) => {
? let email = await db.get('SELECT * FROM emails WHERE id = ?', req.params.id);


? if (!email) {
? ? await db.run('INSERT INTO emails (id, openedAt) VALUES (?, ?)', req.params.id, new Date());
? ? email = { id: req.params.id, openedAt: new Date() };
? }


? const ttl = 60 * 5;? // Destruct in 5 mins, change it as needed
? const currentTime = new Date();
? const timeElapsed = Math.floor((currentTime - new Date(email.openedAt)) / 1000);


? res.json([{ expired: timeElapsed > ttl }]);
});


app.listen(3000, () => {
? console.log('Server started on https://localhost:3000');
});        
No alt text provided for this image
Our NodeJS server


A Node.js server with SQLite, all set and ready! It's got an endpoint for sending an email and another for checking if an email has expired. Now, hold on to your horses as we dive into the magical world of AMP4Email!


Crafting Dynamic Emails with AMP4Email

Dynamic emails, you ask? Indeed! With AMP4Email, our emails can include components that can fetch data from our server, bind it to our email's elements, or even react to the user's actions! So let's draft one.

No alt text provided for this image
Our AMP4Email template flow


We'll use a Gmail account to send our emails. Remember to replace '[email protected]' and 'yourpassword' in the above code with your Gmail email and password. Also make sure you allow less secure apps for this Gmail account.


The amp property of our email will hold our AMP HTML:

<!doctype html>
<html ?4email>
<head>
? <meta charset="utf-8">
? <script async src="https://cdn.ampproject.org/v0.js"></script>
? <style amp4email-boilerplate>body{visibility:hidden}</style>
? <style amp-custom>
? ? .content {
? ? ? display: none;
? ? }
? ? .content:not(.expired) {
? ? ? display: block;
? ? }
? ? .expired-message {
? ? ? display: none;
? ? }
? ? .expired-message.visible {
? ? ? display: block;
? ? }
? </style>
? <script async custom-element="amp-list" src="https://cdn.ampproject.org/v0/amp-list-0.1.js"></script>
</head>
<body>
? <amp-list id="timer" layout="fixed-height" height="0" width="auto"
? ? ? ? ? ? src="https://localhost:3000/email-opened/${id}"
? ? ? ? ? ? single-item
? ? ? ? ? ? items=".">
? ? <template type="amp-mustache">
? ? ? <div class="content" [class]="expired ? 'content expired' : 'content'">
? ? ? ? Confidential message goes here.
? ? ? </div>
? ? ? <div class="expired-message" [class]="expired ? 'expired-message visible' : 'expired-message'">
? ? ? ? This message has self-destructed.
? ? ? </div>
? ? </template>
? </amp-list>
</body>
</html>        


If this is your first time seeing an email with <script> tags, don't fret. It's all part of the magic of AMP4Email. When the email opens, the amp-list component fetches from our /email-opened/:id endpoint. If the TTL has passed, it changes the classes of our divs to show or hide the right message.


Bringing It All Together with React

Time to create a user-friendly interface for our email-sending server. Let's create a new React application:

npx create-react-app email-frontend
cd email-frontend        

Then install the axios, react-draft-wysiwyg, and draftjs-to-html packages:

npm install axios react-draft-wysiwyg draftjs-to-html        

Now, replace the contents of src/App.js with the following:


import React, { useState } from 'react';
import axios from 'axios';
import { Editor } from 'react-draft-wysiwyg';
import { EditorState, convertToRaw } from 'draft-js';
import draftToHtml from 'draftjs-to-html';
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css';

function App() {
? const [editorState, setEditorState] = useState(EditorState.createEmpty());
? const [email, setEmail] = useState('');

? const sendEmail = async () => {
? ? const rawContentState = convertToRaw(editorState.getCurrentContent());
? ? const markup = draftToHtml(rawContentState);
? ? const response = await axios.post('https://localhost:3000/send-email', {
? ? ? email,
? ? ? message: markup
? ? });
? ? alert(`Email sent! Message ID: ${response.data.messageId}`);
? };

? return (
? ? <div className="App">
? ? ? <input type="text" placeholder="Recipient's email" value={email} onChange={e => setEmail(e.target.value)} />
? ? ? <Editor
? ? ? ? editorState={editorState}
? ? ? ? onEditorStateChange={setEditorState}
? ? ? />
? ? ? <button onClick={sendEmail}>Send Email</button>
? ? </div>
? );
}

export default App;        

Our handy interface now has an input for the recipient's email address, a text editor for our confidential message, and a Send button.


Securing the Final Puzzle Piece: Node.js Magic

What's a tech adventure without some server-side wizardry? Now that our React application is ready to craft confidential messages, it's time for our Node.js server to work its charm.


Recall the AMP4Email template we created earlier with a placeholder text saying 'Confidential message goes here'? We'll now bring that into play. Instead of having the template on our client-side React application, we need to incorporate it into our server.


const emailTemplate = `
<!doctype html>
<html ?4email>
<head>
? <meta charset="utf-8">
? <script async src="https://cdn.ampproject.org/v0.js"></script>
? <style amp4email-boilerplate>body{visibility:hidden}</style>
? <style amp-custom>
? ? /* CSS rules go here */
? </style>
</head>
<body>
? <!-- The confidential message placeholder -->
? <p id="confidentialMsg">Confidential message goes here</p>
? <!-- The rest of the AMP4Email markup... -->
</body>
</html>
`;

module.exports = emailTemplate;        

Pretty neat, right? Now, let's use this template in our /send-email route.


We're going to import the template and use the replace function to replace the 'Confidential message goes here' placeholder with the user's actual message. And voila! Our server becomes an expert at crafting self-destructing emails. Here's how you can do it:


const emailTemplate = require('./emailTemplate');


app.post('/send-email', async (req, res) => {
? // ... rest of your code ...


? // Replace the placeholder text with the user's message
? const ampMarkupWithMessage = emailTemplate.replace('Confidential message goes here', req.body.message);


? let info = await transporter.sendMail({
? ? from: '"Fun Times ??" <[email protected]>',
? ? to: req.body.email,
? ? subject: "Self Destruct in 5 Minutes ?",
    html: req.body.message, //if amp is not supported, use html as it was
? ? amp: ampMarkupWithMessage
? });


? // ... rest of your code ...
});        

With this final piece, our server pulls in the AMP4Email template, weaves in the confidential message, and sends it off as an AMP4Email.


Publishing your Project and Google Whitelist Registration

Before we take a final bow, there's an essential step you must be aware of. To make this project fly in the real-world internet skies, you must host it on a publicly accessible URL. This is because our email message needs to reach out to our server, and if it's tucked away in a local development environment, it's going to be like a carrier pigeon with no coordinates. So, whether you favor Heroku, Netlify, AWS, or any other platform, make sure you deploy your project there.


But wait, there's another caveat! You need to register the used 'from' email address with Google. Why, you ask? Because AMP4Email messages require the sender's email address to be whitelisted by Google. It's a necessary step to ensure the safe delivery of dynamic email content. You can register and check the specifics of this process in the Google AMP for Email Registration guide.



Time to test it out! Run your Node.js server with 'node index.js' and start your React app with 'npm start'. You can now send self-destructing emails. Pop open a fresh email, and after 5 minutes, the secret message will self-destruct! Mic drop!



No alt text provided for this image
Image created by the author & Adobe FireFly


This Inspector Gadget inspired adventure has been an absolute delight. Creating self-destructing emails using AMP4Email, Node.js, and SQLite isn't just about mimicking cartoons, it's about exploring the realms of possibility. It's a testament to the fact that with the right tools and a little imagination, the world of software engineering can be a thrilling escapade.


Until next time, happy coding!


#nodejs #react #email


Matías Felipe Varas-Lagos Vergara

Especialista en relacionamiento estratégico empresa - comunidad/ Ayudo a construir relaciones de confianza /Escucha activa / Innovación y creatividad

1 年

Interesante artículo. No hay desafíos imposibles ....Vamos más allá.....

Mauricio Rojas Farías

Liderazgo comercial | Marketing estratégico | Comunicación corporativa

1 年

?Excelente Pablo! ?? muy interesantes tus artículos ??

要查看或添加评论,请登录

Pablo Schaffner Bofill的更多文章

社区洞察

其他会员也浏览了