Advance Use Case
BYOAI (Bring Your Own AI)
For advanced users, you can use your AI or large language model (LLM), such as OpenAI, Claude, etc., to send contextual emails based on events and user activities and guide your users to the next steps (e.g., onboarding, user upgrades, support, retention, and more).
1.) Event listeners.
2.) Access to an AI or LLM.
Example Use Case: Support Chatbot Integration
Here's an AI Agent we created to demonstrate how Lemón can work with your AI model. Give it a try here.
When a conversation ends, the "conversation_ended" event triggers.
If you want implement this, I'd recommend taking a look at our code below for reference:
Javascript
'use server'
import { CoreMessage } from 'ai'
import { generateText } from 'ai'
import { openai } from '@ai-sdk/openai'
// API constants
const LEMON_API_KEY = 'lemón_email_api_key'
const LEMON_API_URL = 'https://app.xn--lemn-sqa.com/api/transactional/send'
/**
* Generates a personalized email based on the conversation history.
*
* @param userName - The name of the user to personalize the email for.
* @param messages - The conversation history.
* @returns A promise that resolves to an object containing the email subject and content.
*/
async function generatePersonalizedEmail(userName: string, messages: CoreMessage[]): Promise<{ subject: string; content: string }> {
// Convert the conversation history into a string format
const conversationSummary = messages.map(m => `${m.role}: ${m.content}`).join('\n')
// Construct the prompt for the AI model
const prompt = `You're a cool, laid-back product manager at a SaaS startup. Based on this chat, write a super casual, friendly email to ${userName}. The goal is to subtly hint at our paid features without being pushy.
Conversation History:
${conversationSummary}
Guidelines:
- Start with "Hey ${userName}," - keep it super casual.
- Write like you're texting a friend. Use slang, contractions, even throw in an emoji or two if it feels natural.
- Briefly mention something specific from their chat to show you were really listening.
- Casually bring up a paid feature that might help them, but do it in a "no pressure" way.
- Instead of a hard sell, just plant a seed of curiosity about the paid stuff.
- Keep it short and sweet - aim for about 50-75 words.
- Break it up into short paragraphs or even single lines for easy reading.
- Sign off casually, like you would to a friend.
- DO NOT sound like AI or use any corporate jargon.
For the subject line:
- Include ${userName}'s name
- Make it lowercase (except for ${userName}'s name)
- Keep it short, casual, and intriguing - like a text message subject
- Max 40 characters
Output format:
Subject: [Your generated subject line]
[Your generated email content]`
try {
// Generate text using the OpenAI model
const { text } = await generateText({
model: openai('gpt-4o'),
prompt: prompt,
maxTokens: 400,
})
if (!text) {
throw new Error('Generated text is empty')
}
// Split the generated text into subject and content
const [subjectLine, ...contentLines] = text.split('\n')
const subject = subjectLine.replace('Subject: ', '').trim()
const content = contentLines.join('\n').trim()
return { subject, content }
} catch (error) {
console.error('Error generating email content:', error)
throw new Error('Failed to generate email content: ' + (error.message || 'Unknown error'))
}
}
/**
* Sends a personalized email using the Lemon API.
*
* @param email - The recipient's email address.
* @param subject - The email subject.
* @param content - The email content (plain text).
* @returns A promise that resolves to an object indicating success or failure.
*/
async function sendPersonalizedEmail(email: string, subject: string, content: string): Promise<{ success: boolean; error?: string }> {
// Convert plain text content to HTML
const htmlContent = content.split('\n').map(paragraph => `<p>${paragraph}</p>`).join('')
// Construct the email payload
const payload = {
fromname: "Example AI (Advanced Use Case)",
fromemail: "mail@elitegci.com",
to: email,
subject: subject,
body: `
<html>
<head>
<style>
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
p { margin-bottom: 15px; }
</style>
</head>
<body>
${htmlContent}
</body>
</html>
`
}
try {
// Set up abort controller for timeout
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 10000) // 10 second timeout
// Send the email using fetch
const response = await fetch(LEMON_API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Auth-APIKey': LEMON_API_KEY
},
body: JSON.stringify(payload),
signal: controller.signal
})
clearTimeout(timeoutId)
if (!response.ok) {
const errorText = await response.text()
console.error('Email API error response:', response.status, errorText)
return { success: false, error: `HTTP error! status: ${response.status}, message: ${errorText}` }
}
return { success: true }
} catch (error) {
console.error('Error sending personalized email:', error)
if (error.name === 'AbortError') {
return { success: false, error: 'Network timeout: Unable to connect to the email service' }
}
if (error instanceof TypeError && error.message.includes('fetch')) {
return { success: false, error: 'Network error: Unable to connect to the email service' }
}
return { success: false, error: error.message || 'Failed to send personalized email' }
}
}
/**
* Analyzes the conversation, generates a personalized email, and sends it.
*
* @param email - The recipient's email address.
* @param userName - The name of the user.
* @param messages - The conversation history.
* @returns A promise that resolves to an object indicating success or failure.
*/
export async function analyzeAndSendEmail(email: string, userName: string, messages: CoreMessage[]) {
try {
// Generate the personalized email content
const { subject, content } = await generatePersonalizedEmail(userName, messages)
// Send the email
const result = await sendPersonalizedEmail(email, subject, content)
return result
} catch (error) {
console.error('Error in analyzeAndSendEmail:', error)
return { success: false, error: error.message || 'Failed to analyze and send email' }
}
}
Python
import asyncio
import aiohttp
from typing import List, Dict, Any, Tuple
import logging
from ai import generateText
from ai_sdk.openai import openai
# Configure logging for better debugging and error tracking
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# API constants
LEMON_API_KEY = 'lemón_email_api_key'
LEMON_API_URL = 'https://app.xn--lemn-sqa.com/api/transactional/send'
async def generate_personalized_email(user_name: str, messages: List[Dict[str, Any]]) -> Tuple[str, str]:
"""
Generate a personalized email based on the conversation history.
This function uses the OpenAI GPT model to generate a casual, friendly email
that subtly hints at paid features without being pushy.
Args:
user_name (str): The name of the user to personalize the email for.
messages (List[Dict[str, Any]]): The conversation history, where each message
is a dictionary with 'role' and 'content' keys.
Returns:
Tuple[str, str]: A tuple containing the subject and content of the generated email.
Raises:
ValueError: If the generated text is empty or invalid.
"""
# Convert the conversation history into a string format
conversation_summary = '\n'.join([f"{m['role']}: {m['content']}" for m in messages])
# Construct the prompt for the AI model
prompt = f"""You're a cool, laid-back product manager at a SaaS startup. Based on this chat, write a super casual, friendly email to {user_name}. The goal is to subtly hint at our paid features without being pushy.
Conversation History:
{conversation_summary}
Guidelines:
- Start with "Hey {user_name}," - keep it super casual.
- Write like you're texting a friend. Use slang, contractions, even throw in an emoji or two if it feels natural.
- Briefly mention something specific from their chat to show you were really listening.
- Casually bring up a paid feature that might help them, but do it in a "no pressure" way.
- Instead of a hard sell, just plant a seed of curiosity about the paid stuff.
- Keep it short and sweet - aim for about 50-75 words.
- Break it up into short paragraphs or even single lines for easy reading.
- Sign off casually, like you would to a friend.
- DO NOT sound like AI or use any corporate jargon.
For the subject line:
- Include {user_name}'s name
- Make it lowercase (except for {user_name}'s name)
- Keep it short, casual, and intriguing - like a text message subject
- Max 40 characters
Output format:
Subject: [Your generated subject line]
[Your generated email content]"""
try:
# Generate text using the OpenAI model
result = await generateText(
model=openai('gpt-4o'),
prompt=prompt,
max_tokens=400
)
text = result.get('text')
if not text:
raise ValueError('Generated text is empty')
# Split the generated text into subject and content
subject_line, *content_lines = text.split('\n')
subject = subject_line.replace('Subject: ', '').strip()
content = '\n'.join(content_lines).strip()
# Validate the generated text
if not subject or not content:
raise ValueError('Invalid generated text format')
return subject, content
except Exception as error:
logger.error(f'Error generating email content: {error}')
raise ValueError(f'Failed to generate email content: {str(error)}')
async def send_personalized_email(email: str, subject: str, content: str) -> Dict[str, Any]:
"""
Send a personalized email using the Lemon API.
This function constructs an HTML email from the given content and sends it
using the Lemon API. It handles various network-related errors and timeouts.
Args:
email (str): The recipient's email address.
subject (str): The email subject.
content (str): The email content (plain text).
Returns:
Dict[str, Any]: A dictionary containing the success status and any error message.
"""
# Convert plain text content to HTML
html_content = ''.join([f'<p>{paragraph}</p>' for paragraph in content.split('\n')])
# Construct the email payload
payload = {
'fromname': "Example AI (Advanced Use Case)",
'fromemail': "mail@elitegci.com",
'to': email,
'subject': subject,
'body': f"""
<html>
<head>
<style>
body {{ font-family: Arial, sans-serif; line-height: 1.6; color: #333; }}
p {{ margin-bottom: 15px; }}
</style>
</head>
<body>
{html_content}
</body>
</html>
"""
}
try:
# Send the email using aiohttp
async with aiohttp.ClientSession() as session:
async with session.post(
LEMON_API_URL,
headers={
'Content-Type': 'application/json',
'X-Auth-APIKey': LEMON_API_KEY
},
json=payload,
timeout=aiohttp.ClientTimeout(total=10) # 10 second timeout
) as response:
if response.status != 200:
error_text = await response.text()
logger.error(f'Email API error response: {response.status}, {error_text}')
return {'success': False, 'error': f'HTTP error! status: {response.status}, message: {error_text}'}
return {'success': True}
except asyncio.TimeoutError:
logger.error('Network timeout: Unable to connect to the email service')
return {'success': False, 'error': 'Network timeout: Unable to connect to the email service'}
except aiohttp.ClientError as error:
logger.error(f'Network error: Unable to connect to the email service - {error}')
return {'success': False, 'error': 'Network error: Unable to connect to the email service'}
except Exception as error:
logger.error(f'Error sending personalized email: {error}')
return {'success': False, 'error': str(error) or 'Failed to send personalized email'}
async def analyze_and_send_email(email: str, user_name: str, messages: List[Dict[str, Any]]) -> Dict[str, Any]:
"""
Analyze the conversation, generate a personalized email, and send it.
This function orchestrates the entire process of generating and sending
a personalized email based on the conversation history.
Args:
email (str): The recipient's email address.
user_name (str): The name of the user.
messages (List[Dict[str, Any]]): The conversation history.
Returns:
Dict[str, Any]: A dictionary containing the success status and any error message.
"""
try:
# Validate input parameters
if not email or not user_name or not messages:
raise ValueError("Missing required parameters")
# Generate the personalized email content
subject, content = await generate_personalized_email(user_name, messages)
# Send the email
result = await send_personalized_email(email, subject, content)
return result
except Exception as error:
logger.error(f'Error in analyze_and_send_email: {error}')
return {'success': False, 'error': str(error) or 'Failed to analyze and send email'}
if __name__ == "__main__":
# Example usage of the analyze_and_send_email function
async def main():
email = "user@example.com"
user_name = "John"
messages = [
{"role": "user", "content": "I'm having trouble with the file upload feature."},
{"role": "assistant", "content": "I'm sorry to hear that. Can you tell me more about the issue?"},
{"role": "user", "content": "It's not accepting PNG files larger than 5MB."},
]
result = await analyze_and_send_email(email, user_name, messages)
print(result)
# Run the example
asyncio.run(main())
More Use Case: Support Chatbot Integration
If the user expressed concerns, it could say:
"Hi [User Name], I understand you had some concerns about delivery times. We’d love to help resolve that for you—here’s a direct line to our support team."
Leverage your LLM (e.g., OpenAI or Claude) to craft a highly personalized follow-up email, encouraging the user to take the next step (e.g., guided onboarding, making a payment, upgrading their plan, etc).
If set up properly, Lemón API will work with your AI/LLM to engage, support, convert, and retain your customers forever.
Why BYOLLM?
We adopt a "Bring Your Own AI" approach to provide flexibility and maintain your users’ privacy.
If your workflow requires accessing sensitive data (e.g., user databases or conversation history), your own AI or LLM ensures that all data processing remains private and under your control.
This enables you to maintain compliance with your organization’s data policies while still benefiting from powerful AI-driven personalization.
This also empowers you to build deeper relationships with your users by combining AI-powered insights with automated, contextually relevant emails.