Editor for Email Template Tags
A tool that provides a complete overview of tags with placeholders for data inputs, allowing for easy customization of email templates. Designed to streamline the process and minimize errors, it automatically populates relevant information in a centralized location.
Demo
- https://editagle.dev.yliang.net/
Features
Configurations of server-side and client-side
-
Client and Server:
- React.js for frontend and Express.js for backend.
- Middleware Multer to handle file uploading.
- Node.js
fs
module to handle document parsing on the server side. - Library Cheerio to handle content manipulation.
-
Client Side Only:
- React.js for frontend.
- Element input type file to handle file uploading.
- Web API
FileReader
object to handle file parsing on the client side. - Library Cheerio to handle content manipulation.
File Uploading
-
Server-side handling
multipart/form-data
with Multer middlewarerouter.use(bodyParser.json()); // for parsing application/json router.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded const upload = multer({ dest: 'uploads/' }); router.post('/:type', upload.any(), (req, res) => { const { type } = req.params; const fields = req.body; switch (type) { case INVENTORY: const templateFilePath = req.files[0].path; const informationFilePath = req.files[1].path; const filePaths = { templateFilePath, informationFilePath }; modInventory({ ...filePaths, ...fields }); res.sendFile(ABSOLUTE_UNLOAD_PATH + INVENTORY_FILE_PATH); break; ... } });
-
Client-side handling
multipart/form-data
with file type input element<form onSubmit={handleSubmit} encType='multipart/form-data'> <input type='file' name='template' onChange={handleFileChange} /> <input type='file' name='information' onChange={handleFileChange} /> ... <textarea name={name} onChange={handleFieldChange}/> </form> ... const [files, setFiles] = useState([]); const handleFileChange = async (e) => { const file = e.target.files[0]; if (file?.size > 1024 * 1000) { alert('File size cannot exceed more than 1MB'); } else { setFiles({ ...files, [e.target.name]: file }); } }; const [fields, setFields] = useState([]); const handleFieldChange = async (e) => { setFields({ ...fields, [e.target.name]: e.target.value.trim() }); }
Document Parsing
-
Server-side Node.js
fs
Module// on the server const templateHtml = fs.readFileSync(templateFilePath).toString(); // email html const informationJson = fs.readFileSync(informationFilePath); // json array ... fs.writeFileSync(ABSOLUTE_UNLOAD_PATH + INVENTORY_FILE_PATH, template.html()); // on the client const res = await fetch(`${BASE_URL}/${type}`, { method: 'POST', body: formData }); ... const data = await res.blob(); const url = window.URL.createObjectURL(data);
-
Client-side Web API
FileReader
Objectconst templateReader = new FileReader(); const informationReader = new FileReader(); templateReader.readAsText(template); informationReader.readAsText(information); const templatePromise = new Promise((resolve, reject) => { templateReader.addEventListener('load', () => { resolve(templateReader.result); }); }); const informationPromise = new Promise((resolve, reject) => { informationReader.addEventListener('load', () => { resolve(informationReader.result); }); }); const [templateHtml, informationJson] = await Promise.all([templatePromise, informationPromise]); ... const blob = new Blob([template.html()], { type: 'text/html' }); const url = window.URL.createObjectURL(blob);
Summary
-
The Why
The idea for this tool stems from my own experience working as a web designer, where one of my responsibilities was to develop email templates from the ground up and update them with current content on a weekly basis. This entailed repeatedly replacing images, links, and text. For more complex designs, the process of editing and updating email templates can be time-consuming and labor-intensive. Even with an email builder, it can be cumbersome to navigate. I realized that if there was a way to access and view all of the elements’ attributes, such as image sources and hyperlinks, it can help reduce the time and effort required.
-
The How
In the beginning, I build a command-line program with just Cheerio.js and Node.js to parse and manipulate HTML files. To have an easy-to-use interface, I then built a backend using Express and a frontend with React. Since file processing can be handled directly by the browser, eliminating the need for a backend. Upon further consideration of file handling security, I shifted my focus to developing only a web-based solution for what would the application that allows users to edit images, links, text, and titles by associating editable fields with the class names of HTML tags.
To customize a template with different images, links, and texts, fill in the corresponding fields with the new values.
To edit an existing template, upload the template, specify the classes of the tags to be changed, and enter the relevant information.
-
The What
The demo application offers three options for template customization. The first option allows users to personalize a pre-existing template through the predefined input fields. The second option enables users to upload their own template and specify class names for editable regions. The third option facilitates the creation of a data table within a template, complete with rows and columns, by user-provided HTML and JSON files. The application features a centralized location for all input fields for viewing and editing fields without having to navigate between tags and lines of code. Additionally, there is a preview of the rendered template that updates in real-time as changes are made.