Keeping users engaged is crucial to any application’s success. Automated email summaries provide an effective way to achieve this by delivering curated content that keeps users connected to your platform. In this tutorial, we’ll guide you through building an AI-enabled automated email summary system with continuous integration and deployment (CI/CD) using Semaphore.
PrerequisitesBefore starting this tutorial, you should have:
All of the code for this article is available at ajcwebdev/semaphore-ai-email. Begin by cloning this repo, creating a .env file, and installing the project’s dependencies:
git clone https://github.com/ajcwebdev/semaphore-ai-emailcd semaphore-ai-emailcp .env.example .envnpm i
Step 1: Setting Up the Email Service and TemplatesWe’ll begin by creating the foundation of our email summary system: the email service and templates. This step involves setting up Nodemailer for email sending and designing responsive HTML templates for our summaries.
First, open the file named send-email.js. This script will handle the email sending process:
// send-email.jsimport nodemailer from 'nodemailer'import { fileURLToPath } from 'url'import { dirname, join } from 'path'import fs from 'fs/promises'const __filename = fileURLToPath(import.meta.url)const __dirname = dirname(__filename)async function sendEmail() { let transporter = nodemailer.createTransport({ host: process.env.EMAIL_HOST, port: 587, auth: { user: process.env.EMAIL_USER, pass: process.env.EMAIL_PASS } }) const htmlTemplate = await fs.readFile(join(__dirname, 'email-template.html'), 'utf-8') let mailOptions = { from: `"Test Email" <${process.env.EMAIL_USER}>`, to: process.env.EMAIL_USER, subject: 'Weekly Update', html: htmlTemplate } let info = await transporter.sendMail(mailOptions) console.log('Message sent: %s', info.messageId) console.log('Preview URL: %s', nodemailer.getTestMessageUrl(info))}async function main() { try { await sendEmail() console.log('Email sent successfully. Waiting 1 week before sending the next one...') } catch (error) { console.error('Failed to send email:', error) } await new Promise(resolve => setTimeout(resolve, 7 * 24 * 60 * 60 * 1000))}main().catch(console.error)
This script sets up a Nodemailer transporter using Ethereal Email, a catch-all email testing service. Ethereal is ideal for development as it captures emails without actually sending them, providing a preview URL for each message.
Let’s break down the key components:
fs.promises to read the template and CSS files asynchronously.This script references two articles selected and saved in files called ARTICLE_1.js and ARTICLE_2.js. You can use the examples provided in my repo or replace them with your own. The files are structured like so (see example repo for entire file contents):
``
// ARTICLE_1.jsexport const ARTICLE_1 = { title: "Why you should write your own LLM benchmarks - with Nicholas Carlini, Google DeepMind", content:Today's guest, Nicholas Carlini, a research scientist at DeepMind, argues that we should be focusing more on what AI can do for us individually, rather than trying to have an answer for everyone....,}// ARTICLE\_2.jsexport const ARTICLE\_2 = { title: "Why you should write your own LLM benchmarks - with Nicholas Carlini, Google DeepMind", content:Betteridge's law says no: with seemingly infinite flavors of RAG, and >2million token context + prompt caching from Anthropic/Deepmind/Deepseek, it's reasonable to believe that \"in context learning is all you need\".
...,}**
```
**Next, open the HTML email template namedemail-template.html. The AI summaries we’ll generate in the next section are contained within themain` tags.
``
**Weekly AI Newsletter Weekly AI Newsletter Your weekly digest of AI news and insights
Top Articles Why you should write your own LLM benchmarks — with Nicholas Carlini, Google DeepMind The article features an interview with Nicholas Carlini, a research scientist at DeepMind, discussing his views on AI and his work in AI security. Key points include:
Is finetuning GPT4o worth it? — with Alistair Pullen, Cosine (Genie) This article discusses an interview with Alistair Pullen, CEO and co-founder of Cosine, about their new AI coding agent called Genie. Key points include:
© 2024 Weekly AI Newsletter. All rights reserved.
Unsubscribe | View in browser | Privacy Policy` ``` This HTML template provides the structure for our email. It includes:**
The CSS defines the styles for our email template. Key features include:
In the next step, we’ll focus on content aggregation and processing, where we’ll use AI to generate summaries for our newsletter.
Step 2: Content Aggregation and ProcessingIn this step, we’ll use Anthropic’s Claude API to automatically summarize articles for our email digest. This process involves interacting with an advanced language model to generate concise, informative summaries of longer articles.
Open the file named claude.js:
**`// claude.jsimport Anthropic from '@anthropic-ai/sdk'import { ARTICLE_1 } from './ARTICLE_1.js'import { ARTICLE_2 } from './ARTICLE_2.js'const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY})async function summarizeArticle(article) { const prompt = `Please provide a one to two paragraph summary of the following article:${article}Summary:` const response = await anthropic.messages.create({ model: "claude-3-5-sonnet-20240620", max_tokens: 300, messages: [ { role: "user", content: prompt } ] }) return response.content[0].text}async function processArticles(articles) { const summaries = [] for (const article of articles) { const { title, content } = article const summary = await summarizeArticle(content) summaries.push({ title, summary }) console.log(`Summarized: ${title}`) } return summaries}async function main() { const articles = [ { title: ARTICLE_1.title, content: ARTICLE_1.content }, { title: ARTICLE_2.title, content: ARTICLE_2.content } ] try { const results = await processArticles(articles) for (const result of results) { console.log(`\nTitle: ${result.title}`) console.log(`Summary: ${result.summary}`) console.log("-".repeat(50)) } } catch (error) { console.error("An error occurred:", error) }}main()`**
Let’s break down this script and examine its key components:
summarizeArticle function takes an article’s content and sends it to Claude with a specific prompt. We use the “claude-3-5-sonnet-20240620” model and limit the response to 300 tokens for concise summaries. The function returns the generated summary.processArticles function iterates through an array of articles, calling summarizeArticle for each one. It collects the title and generated summary for each article and returns an array of these summaries.main function defines an array of articles (in a real-world scenario, this data might come from an external source). It then calls processArticles and logs the results. Error handling is implemented to catch and log any issues that occur during processing.main function to start the summarization process.Open the .env file and include your Anthropic API key:
**`ANTHROPIC_API_KEY=""`**
Run the script with the following command:
**`npm run claude`**
This script demonstrates using AI for content processing. By using Claude’s natural language understanding capabilities, we can automatically generate concise summaries of lengthy articles. The next step will involve setting up automated deployment with Semaphore.
Step 3: Automating the Build and Deploy Process with SemaphoreIn this step, we’ll set up a continuous integration and deployment (CI/CD) pipeline using Semaphore. This will automate our build process and schedule our weekly email digest.
The semaphore.yml file in the .semaphore directory contains the specific steps for sending the email. This allows separating the weekly email task from the regular CI/CD pipeline.
**`# .semaphore/semaphore.ymlversion: v1.0name: Send Weekly Emailagent: machine: type: e1-standard-2 os_image: ubuntu2004blocks: - name: Send Email task: secrets: - name: email-credentials jobs: - name: Send Email commands: - checkout - sem-version node 20 - npm install nodemailer - node send-email.js`**
1. *Set up Semaphore project:* To set up your Semaphore project, first create a Semaphore account, open your organization settings, and navigate to the Secrets section:
2. Create secrets: Click “New Secret” and name the secret email-credentials. Set your test email to EMAIL_USER, your password to EMAIL_PASS, and your email host provider to EMAIL_HOST.
3. Save and connect: Click “Save Secret.” Next, create a new project and connect the project to your GitHub repository:
4. Run workflow: This will start running your workflow:
5. View logs: Click “Send Email” to view the workflow logs:
6. Check results: Your logs should include a message saying, “Message sent” along with a preview URL. Open the preview URL to view the example email:
This separate pipeline file focuses solely on the tasks required to send your weekly email. By setting up this Semaphore configuration, you’ve automated your build process and scheduled your weekly email digest. Remember to regularly review your Semaphore logs to ensure everything is running smoothly and to catch any potential issues early.
Step 4: Analyzing and Optimizing Summary EmailsTo improve our email summaries over time, we should implement analytics to track open rates and engagement. We can set up A/B testing for subject lines and content layouts. Here’s how:
Step 5: Scaling, Cost Optimization, and DeliverabilityAs your user base grows, consider these strategies for scaling:
A caching mechanism can significantly reduce the number of API calls to Claude, lowering costs and improving response times.
To ensure email deliverability and prevent your domain from being blacklisted for spam, implement the following best practices:
By implementing these practices and closely monitoring your email performance, you can maintain a strong sender reputation, ensure high deliverability rates, and prevent your domain from being blacklisted.
ConclusionWe’ve built an AI-enabled automated email summary system with CI/CD capabilities. This system aggregates content, uses AI to generate summaries, and sends personalized email digests to users. By leveraging Semaphore’s CI/CD pipeline, we ensure consistent, automated deployments.
To maintain and evolve this system:
Remember, while we used Ethereal Email for testing, you’ll want to switch to a production-ready email service provider when you’re ready to send to real users.
Start building your own automated email summary system today by setting up your Semaphore pipeline and integrating AI-powered content summarization.
Additional ResourcesTo further your understanding of the technologies and concepts used in this tutorial, consider exploring these resources:
By following this tutorial and exploring these additional resources, you’ll be well-equipped to create and maintain a sophisticated, AI-powered email summary system that keeps your users engaged and informed.
The post Building an AI-Enabled Automated Email Summary System with CI/CD appeared first on Semaphore.