import { promises as fs } from 'fs'
import path from 'path'
import { randomUUID } from 'crypto'
export interface EmailAttachment {
filename: string
content: Buffer
cid: string
}
interface AgentEmailParams {
agentName: string
content: string
appUrl: string
userName?: string
}
/**
* Read a local image file from the public directory.
*/
async function readLocalImage(relativePath: string): Promise
')
// Headings
html = html.replace(/^### (.+)$/gm, '$1
')
html = html.replace(/^## (.+)$/gm, '$1
')
html = html.replace(/^# (.+)$/gm, '$1
')
// Bold and italic
html = html.replace(/\*\*(.+?)\*\*/g, '$1')
html = html.replace(/\*(.+?)\*/g, '$1')
// Unordered list items
html = html.replace(/^(\s*)[-*] (.+)$/gm, '$1
html = html.replace(/((?:
' + match + '
'
})
// Images  — local images become CID attachments, external stay as-is
const imageMatches = [...html.matchAll(/!\[([^\]]*)\]\(([^)]+)\)/g)]
for (const match of imageMatches) {
const [fullMatch, alt, url] = match
let imgTag: string
if (url.startsWith('/uploads/')) {
// Local image: read file and attach as CID
const buffer = await readLocalImage(url)
if (buffer) {
const cid = `img-${randomUUID()}`
const ext = path.extname(url).toLowerCase() || '.jpg'
attachments.push({ filename: `image${ext}`, content: buffer, cid })
imgTag = ``
} else {
// Fallback to absolute URL if file not found
imgTag = `
`
}
} else {
imgTag = `
`
}
html = html.replace(fullMatch, imgTag)
}
// Links
html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_match, text, url) => {
const absoluteUrl = url.startsWith('/') ? `${baseUrl}${url}` : url
return `${text}`
})
// Paragraphs
html = html.replace(/\n\n+/g, '
')
html = html.replace(/\n/g, '
')
html = '
' + html + '
' html = html.replace(/]*>\s*<\/p>/g, '') return { html, attachments } } export async function getAgentEmailTemplate({ agentName, content, appUrl, userName }: AgentEmailParams): Promise<{ html: string; attachments: EmailAttachment[] }> { const greeting = userName ? `Bonjour ${userName},` : 'Bonjour,' const { html: htmlContent, attachments } = await markdownToEmailHtml(content, appUrl) // Extract a preview (first ~150 chars of plain text for subtitle) const plainText = content .replace(/^#{1,3}\s+/gm, '') .replace(/\*\*/g, '') .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') .replace(/[-*]\s+/g, '') .replace(/\n+/g, ' ') .trim() const html = `
${greeting}
Votre agent ${agentName} a terminé son exécution. Voici les résultats :