# app/api/v1/vendor/email_settings.py """ Vendor email settings API endpoints. Allows vendors to configure their email sending settings: - SMTP configuration (all tiers) - Advanced providers: SendGrid, Mailgun, SES (Business+ tier) - Sender identity (from_email, from_name, reply_to) - Signature/footer customization - Configuration verification via test email Vendor Context: Uses token_vendor_id from JWT token (authenticated vendor API pattern). """ import logging from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel, EmailStr, Field from sqlalchemy.orm import Session from app.api.deps import get_current_vendor_api from app.core.database import get_db from app.exceptions import NotFoundError, ValidationError, AuthorizationError from app.services.vendor_email_settings_service import VendorEmailSettingsService from app.services.subscription_service import subscription_service from models.database.user import User router = APIRouter(prefix="/email-settings") logger = logging.getLogger(__name__) # ============================================================================= # SCHEMAS # ============================================================================= class EmailSettingsUpdate(BaseModel): """Schema for creating/updating email settings.""" # Sender Identity (Required) from_email: EmailStr = Field(..., description="Sender email address") from_name: str = Field(..., min_length=1, max_length=100, description="Sender name") reply_to_email: EmailStr | None = Field(None, description="Reply-to email address") # Signature (Optional) signature_text: str | None = Field(None, description="Plain text signature") signature_html: str | None = Field(None, description="HTML signature/footer") # Provider provider: str = Field("smtp", description="Email provider: smtp, sendgrid, mailgun, ses") # SMTP Settings smtp_host: str | None = Field(None, description="SMTP server hostname") smtp_port: int | None = Field(587, ge=1, le=65535, description="SMTP server port") smtp_username: str | None = Field(None, description="SMTP username") smtp_password: str | None = Field(None, description="SMTP password") smtp_use_tls: bool = Field(True, description="Use STARTTLS") smtp_use_ssl: bool = Field(False, description="Use SSL/TLS (port 465)") # SendGrid sendgrid_api_key: str | None = Field(None, description="SendGrid API key") # Mailgun mailgun_api_key: str | None = Field(None, description="Mailgun API key") mailgun_domain: str | None = Field(None, description="Mailgun sending domain") # SES ses_access_key_id: str | None = Field(None, description="AWS access key ID") ses_secret_access_key: str | None = Field(None, description="AWS secret access key") ses_region: str | None = Field("eu-west-1", description="AWS region") class VerifyEmailRequest(BaseModel): """Schema for verifying email settings.""" test_email: EmailStr = Field(..., description="Email address to send test email to") # ============================================================================= # ENDPOINTS # ============================================================================= @router.get("") def get_email_settings( current_user: User = Depends(get_current_vendor_api), db: Session = Depends(get_db), ): """ Get current email settings for the vendor. Returns settings with sensitive fields masked. """ vendor_id = current_user.token_vendor_id service = VendorEmailSettingsService(db) settings = service.get_settings(vendor_id) if not settings: return { "configured": False, "settings": None, "message": "Email settings not configured. Configure SMTP to send emails to customers.", } return { "configured": settings.is_configured, "verified": settings.is_verified, "settings": settings.to_dict(), } @router.get("/status") def get_email_status( current_user: User = Depends(get_current_vendor_api), db: Session = Depends(get_db), ): """ Get email configuration status. Used by frontend to show warning banner if not configured. """ vendor_id = current_user.token_vendor_id service = VendorEmailSettingsService(db) return service.get_status(vendor_id) @router.get("/providers") def get_available_providers( current_user: User = Depends(get_current_vendor_api), db: Session = Depends(get_db), ): """ Get available email providers for current tier. Returns list of providers with availability status. """ vendor_id = current_user.token_vendor_id service = VendorEmailSettingsService(db) # Get vendor's current tier tier = subscription_service.get_current_tier(db, vendor_id) return { "providers": service.get_available_providers(tier), "current_tier": tier.value if tier else None, } @router.put("") def update_email_settings( data: EmailSettingsUpdate, current_user: User = Depends(get_current_vendor_api), db: Session = Depends(get_db), ): """ Create or update email settings. Premium providers (SendGrid, Mailgun, SES) require Business+ tier. """ vendor_id = current_user.token_vendor_id service = VendorEmailSettingsService(db) # Get vendor's current tier for validation tier = subscription_service.get_current_tier(db, vendor_id) try: settings = service.create_or_update( vendor_id=vendor_id, data=data.model_dump(exclude_unset=True), current_tier=tier, ) return { "success": True, "message": "Email settings updated successfully", "settings": settings.to_dict(), } except AuthorizationError as e: raise HTTPException(status_code=403, detail=str(e)) except ValidationError as e: raise HTTPException(status_code=400, detail=str(e)) @router.post("/verify") def verify_email_settings( data: VerifyEmailRequest, current_user: User = Depends(get_current_vendor_api), db: Session = Depends(get_db), ): """ Verify email settings by sending a test email. Sends a test email to the provided address and updates verification status. """ vendor_id = current_user.token_vendor_id service = VendorEmailSettingsService(db) try: result = service.verify_settings(vendor_id, data.test_email) if result["success"]: return result else: raise HTTPException(status_code=400, detail=result["message"]) except NotFoundError as e: raise HTTPException(status_code=404, detail=str(e)) except ValidationError as e: raise HTTPException(status_code=400, detail=str(e)) @router.delete("") def delete_email_settings( current_user: User = Depends(get_current_vendor_api), db: Session = Depends(get_db), ): """ Delete email settings. Warning: This will disable email sending for the vendor. """ vendor_id = current_user.token_vendor_id service = VendorEmailSettingsService(db) if service.delete(vendor_id): return {"success": True, "message": "Email settings deleted"} else: raise HTTPException(status_code=404, detail="Email settings not found")