Files
gremiumhub/landing/server/api/contact/send.post.ts

136 lines
4.1 KiB
TypeScript

import { z } from 'zod'
const contactSchema = z.object({
name: z.string().min(1).max(100),
email: z.string().email(),
message: z.string().min(10).max(5000)
})
export default defineEventHandler(async (event) => {
const config = useRuntimeConfig()
// Validate request body
const body = await readBody(event)
const result = contactSchema.safeParse(body)
if (!result.success) {
throw createError({
statusCode: 400,
statusMessage: 'Invalid form data',
data: result.error.flatten()
})
}
const { name, email, message } = result.data
// Check if API key is configured
if (!config.brevoApiKey || config.brevoApiKey === 'NOT_SET') {
console.error('BREVO_API_KEY is not configured')
throw createError({
statusCode: 500,
statusMessage: 'Email service is not configured'
})
}
try {
// Build HTML email content
const htmlContent = `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; }
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
.header { background: linear-gradient(135deg, #0ea5e9, #06b6d4); color: white; padding: 24px; border-radius: 12px 12px 0 0; }
.content { background: #f8fafc; padding: 24px; border: 1px solid #e2e8f0; border-top: none; border-radius: 0 0 12px 12px; }
.field { margin-bottom: 16px; }
.label { font-weight: 600; color: #64748b; font-size: 12px; text-transform: uppercase; letter-spacing: 0.5px; }
.value { margin-top: 4px; padding: 12px; background: white; border-radius: 8px; border: 1px solid #e2e8f0; }
.message-value { white-space: pre-wrap; }
.footer { margin-top: 24px; padding-top: 16px; border-top: 1px solid #e2e8f0; font-size: 12px; color: #94a3b8; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1 style="margin: 0; font-size: 24px;">Neue Kontaktanfrage</h1>
<p style="margin: 8px 0 0; opacity: 0.9;">über GremiumHub Website</p>
</div>
<div class="content">
<div class="field">
<div class="label">Name</div>
<div class="value">${escapeHtml(name)}</div>
</div>
<div class="field">
<div class="label">E-Mail</div>
<div class="value"><a href="mailto:${escapeHtml(email)}">${escapeHtml(email)}</a></div>
</div>
<div class="field">
<div class="label">Nachricht</div>
<div class="value message-value">${escapeHtml(message)}</div>
</div>
<div class="footer">
Diese Nachricht wurde über das Kontaktformular auf gremiumhub.de gesendet.
</div>
</div>
</div>
</body>
</html>
`.trim()
// Send email via Brevo SMTP API
const response = await $fetch<{ messageId?: string }>('https://api.brevo.com/v3/smtp/email', {
method: 'POST',
headers: {
'api-key': config.brevoApiKey,
'Content-Type': 'application/json'
},
body: {
sender: {
name: config.brevoSenderName,
email: config.brevoSenderEmail
},
to: [
{
email: config.brevoContactEmail,
name: 'GremiumHub Team'
}
],
replyTo: {
email,
name
},
subject: `Kontaktanfrage von ${name}`,
htmlContent
}
})
return {
success: true,
messageId: response.messageId
}
} catch (error: unknown) {
const fetchError = error as { statusCode?: number; data?: { code?: string; message?: string } }
console.error('Brevo SMTP API error:', fetchError.data || error)
throw createError({
statusCode: fetchError.statusCode || 500,
statusMessage: fetchError.data?.message || 'Failed to send message'
})
}
})
// Helper function to escape HTML special characters
function escapeHtml(text: string): string {
const htmlEntities: Record<string, string> = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;'
}
return text.replace(/[&<>"']/g, (char) => htmlEntities[char] ?? char)
}