diff --git a/backend/api.py b/backend/api.py
index 0e8cc709..75f7c295 100644
--- a/backend/api.py
+++ b/backend/api.py
@@ -19,6 +19,8 @@ from agent import api as agent_api
from sandbox import api as sandbox_api
from services import billing as billing_api
from services import transcription as transcription_api
+from services import email_api
+
# Load environment variables (these will be available through config)
load_dotenv()
@@ -136,6 +138,8 @@ app.include_router(billing_api.router, prefix="/api")
# Include the transcription router with a prefix
app.include_router(transcription_api.router, prefix="/api")
+app.include_router(email_api.router, prefix="/api")
+
@app.get("/api/health")
async def health_check():
"""Health check endpoint to verify API is working."""
diff --git a/backend/requirements.txt b/backend/requirements.txt
index 3e7d0eba..3e6e6464 100644
--- a/backend/requirements.txt
+++ b/backend/requirements.txt
@@ -35,3 +35,5 @@ prometheus-client>=0.21.1
langfuse>=2.60.5
Pillow>=10.0.0
sentry-sdk[fastapi]>=2.29.1
+email-validator>=2.0.0
+mailtrap>=3.0.0
\ No newline at end of file
diff --git a/backend/services/email.py b/backend/services/email.py
new file mode 100644
index 00000000..9e9230df
--- /dev/null
+++ b/backend/services/email.py
@@ -0,0 +1,188 @@
+import os
+import logging
+from typing import Optional
+import mailtrap as mt
+from utils.config import config
+
+logger = logging.getLogger(__name__)
+
+class EmailService:
+ def __init__(self):
+ self.api_token = os.getenv('MAILTRAP_API_TOKEN')
+ self.sender_email = os.getenv('MAILTRAP_SENDER_EMAIL', 'dom@kortix.ai')
+ self.sender_name = os.getenv('MAILTRAP_SENDER_NAME', 'Suna Team')
+
+ if not self.api_token:
+ logger.warning("MAILTRAP_API_TOKEN not found in environment variables")
+ self.client = None
+ else:
+ self.client = mt.MailtrapClient(token=self.api_token)
+
+ def send_welcome_email(self, user_email: str, user_name: Optional[str] = None) -> bool:
+ if not self.client:
+ logger.error("Cannot send email: MAILTRAP_API_TOKEN not configured")
+ return False
+
+ if not user_name:
+ user_name = user_email.split('@')[0].title()
+
+ subject = "🎉 Welcome to Suna — Let's Get Started "
+ html_content = self._get_welcome_email_template(user_name)
+ text_content = self._get_welcome_email_text(user_name)
+
+ return self._send_email(
+ to_email=user_email,
+ to_name=user_name,
+ subject=subject,
+ html_content=html_content,
+ text_content=text_content
+ )
+
+ def _send_email(
+ self,
+ to_email: str,
+ to_name: str,
+ subject: str,
+ html_content: str,
+ text_content: str
+ ) -> bool:
+ try:
+ mail = mt.Mail(
+ sender=mt.Address(email=self.sender_email, name=self.sender_name),
+ to=[mt.Address(email=to_email, name=to_name)],
+ subject=subject,
+ text=text_content,
+ html=html_content,
+ category="welcome"
+ )
+
+ response = self.client.send(mail)
+
+ logger.info(f"Welcome email sent to {to_email}. Response: {response}")
+ return True
+
+ except Exception as e:
+ logger.error(f"Error sending email to {to_email}: {str(e)}")
+ return False
+
+ def _get_welcome_email_template(self, user_name: str) -> str:
+ return f"""
+
+
+
+
+ Welcome to Kortix Suna
+
+
+
+
+
+

+
+
Welcome to Kortix Suna!
+
+
Hi {user_name},
+
+
Welcome to Kortix Suna — we're excited to have you on board!
+
+
To get started, we'd like to get to know you better: fill out this short form!
+
+
To celebrate your arrival, here's a 15% discount to try out the best version of Suna (1 month):
+
+
🎁 Use code WELCOME15 at checkout.
+
+
Let us know if you need help getting started or have questions — we're always here, and join our Discord community.
+
+
Thanks again, and welcome to the Suna community 🌞
+
+
— The Suna Team
+
+
Go to the platform
+
+
+"""
+
+ def _get_welcome_email_text(self, user_name: str) -> str:
+ return f"""Hi {user_name},
+
+Welcome to Suna — we're excited to have you on board!
+
+To get started, we'd like to get to know you better: fill out this short form!
+https://docs.google.com/forms/d/e/1FAIpQLSef1EHuqmIh_iQz-kwhjnzSC3Ml-V_5wIySDpMoMU9W_j24JQ/viewform
+
+To celebrate your arrival, here's a 15% discount to try out the best version of Suna (1 month):
+🎁 Use code WELCOME15 at checkout.
+
+Let us know if you need help getting started or have questions — we're always here, and join our Discord community: https://discord.com/invite/FjD644cfcs
+
+Thanks again, and welcome to the Suna community 🌞
+
+— The Suna Team
+
+Go to the platform: https://www.suna.so/
+
+---
+© 2024 Suna. All rights reserved.
+You received this email because you signed up for a Suna account."""
+
+email_service = EmailService()
diff --git a/backend/services/email_api.py b/backend/services/email_api.py
new file mode 100644
index 00000000..9834c7ba
--- /dev/null
+++ b/backend/services/email_api.py
@@ -0,0 +1,70 @@
+from fastapi import APIRouter, HTTPException, Depends
+from pydantic import BaseModel, EmailStr
+from typing import Optional
+import asyncio
+from services.email import email_service
+from utils.logger import logger
+
+router = APIRouter()
+
+class SendWelcomeEmailRequest(BaseModel):
+ email: EmailStr
+ name: Optional[str] = None
+
+class EmailResponse(BaseModel):
+ success: bool
+ message: str
+
+@router.post("/send-welcome-email", response_model=EmailResponse)
+async def send_welcome_email(request: SendWelcomeEmailRequest):
+ try:
+ logger.info(f"Sending welcome email to {request.email}")
+ success = email_service.send_welcome_email(
+ user_email=request.email,
+ user_name=request.name
+ )
+
+ if success:
+ return EmailResponse(
+ success=True,
+ message="Welcome email sent successfully"
+ )
+ else:
+ return EmailResponse(
+ success=False,
+ message="Failed to send welcome email"
+ )
+
+ except Exception as e:
+ logger.error(f"Error sending welcome email to {request.email}: {str(e)}")
+ raise HTTPException(
+ status_code=500,
+ detail="Internal server error while sending email"
+ )
+
+@router.post("/send-welcome-email-background", response_model=EmailResponse)
+async def send_welcome_email_background(request: SendWelcomeEmailRequest):
+ try:
+ logger.info(f"Queuing welcome email for {request.email}")
+
+ def send_email():
+ return email_service.send_welcome_email(
+ user_email=request.email,
+ user_name=request.name
+ )
+
+ import concurrent.futures
+ with concurrent.futures.ThreadPoolExecutor() as executor:
+ future = executor.submit(send_email)
+
+ return EmailResponse(
+ success=True,
+ message="Welcome email queued for sending"
+ )
+
+ except Exception as e:
+ logger.error(f"Error queuing welcome email for {request.email}: {str(e)}")
+ raise HTTPException(
+ status_code=500,
+ detail="Internal server error while queuing email"
+ )
diff --git a/frontend/src/app/auth/actions.ts b/frontend/src/app/auth/actions.ts
index 0d092fad..f9ed1074 100644
--- a/frontend/src/app/auth/actions.ts
+++ b/frontend/src/app/auth/actions.ts
@@ -3,6 +3,30 @@
import { createClient } from '@/lib/supabase/server';
import { redirect } from 'next/navigation';
+async function sendWelcomeEmail(email: string, name?: string) {
+ try {
+ const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL;
+ const response = await fetch(`${backendUrl}/send-welcome-email-background`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ email,
+ name,
+ }),
+ });
+
+ if (response.ok) {
+ console.log(`Welcome email queued for ${email}`);
+ } else {
+ console.error(`Failed to queue welcome email for ${email}`);
+ }
+ } catch (error) {
+ console.error('Error sending welcome email:', error);
+ }
+}
+
export async function signIn(prevState: any, formData: FormData) {
const email = formData.get('email') as string;
const password = formData.get('password') as string;
@@ -64,12 +88,17 @@ export async function signUp(prevState: any, formData: FormData) {
return { message: error.message || 'Could not create account' };
}
- // Try to sign in immediately
- const { error: signInError } = await supabase.auth.signInWithPassword({
+ const userName = email.split('@')[0].replace(/[._-]/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
+
+ const { error: signInError, data: signInData } = await supabase.auth.signInWithPassword({
email,
password,
});
+ if (signInData) {
+ sendWelcomeEmail(email, userName);
+ }
+
if (signInError) {
return {
message: