Cold mail generation components
React pieces for drafting cold emails from a resume and job post.
Repository layout#
The cold mail generation feature spans both frontend and backend components:
- Frontend: React components for capturing user input, displaying generated emails, and managing loading states
- Backend: FastAPI routes and services orchestrating LLM-based email generation and editing
- Shared: TypeScript types and service abstractions for API communication
graph TB subgraph "Frontend" A["EmailDetailsForm.tsx"] B["GeneratedEmailPanel.tsx"] C["LoadingOverlay.tsx"] D["PageLoader.tsx"] E["ResumeSelection.tsx"] F["page.tsx"] G["cold-mail.service.ts"] H["cold-mail.ts"] I["use-cold-mails.ts"] end subgraph "Backend" J["cold_mail.py"] K["request.py"] L["response.py"] M["cold_mail_gen.py"] N["cold_mail_editor.py"] end F --> A F --> B F --> C F --> D F --> E F --> G G --> J J --> M J --> N K --> J L --> J
Building blocks#
This section outlines the primary components involved in the cold mail generation workflow:
- EmailDetailsForm: Captures recipient and context information including name, designation, company, sender details, goals, website, key points to highlight, and additional context.
- GeneratedEmailPanel: Displays the generated email subject and body, supports editing mode with instructions, copying to clipboard, and downloading as text.
- LoadingOverlay: Provides modal feedback during generation and editing operations with customizable titles and descriptions.
- PageLoader: Shows a page-level loader during initial load.
- ResumeSelection: Manages three modes, existing resume, uploaded resume, and custom draft editing, along with file previews and optional resume enhancement.
- Service Layer: cold-mail.service.ts encapsulates API calls for retrieving user resumes, generating cold mails, and editing existing emails.
- Types: Defines request/response shapes for cold mail operations.
- Backend Routes: FastAPI endpoints for cold mail generation and editing, supporting both file-based and text-based inputs.
How it fits together#
The system follows a React-based frontend with a modular component architecture and integrates with backend FastAPI endpoints. The workflow supports three input modes: existing resume, uploaded resume, and custom draft editing. The backend applies structured prompts to generate or refine cold emails using an LLM pipeline.
sequenceDiagram
participant U as "User"
participant P as "page.tsx"
participant S as "cold-mail.service.ts"
participant R as "cold_mail.py"
participant T as "cold_mail_gen.py / cold_mail_editor.py"
U->>P : Fill form and select resume/draft
P->>P : Validate inputs and prepare FormData
P->>S : generateColdMail(formData) or editColdMail(formData)
S->>R : POST /cold-mail/generator/ or /cold-mail/edit/
R->>T : Build prompt chain with LLM
T-->>R : Return {subject, body}
R-->>S : ColdMailResponse
S-->>P : Success callback
P->>P : Update generatedEmail state
P->>U : Display email in GeneratedEmailPanelEmailDetailsForm#
Purpose:
- Collects recipient information (name, designation), company details, sender identity, goals, optional website, and contextual content for personalization.
Key behaviors:
- Two-column layout for compact desktop/mobile layouts.
- Controlled inputs bound to parent state via handleInputChange.
- Uses accessible labels and placeholders aligned with brand styling.
Validation and UX:
- Required fields enforced at generation time in the parent page component.
- Optional fields allow flexible customization.
Accessibility and styling:
- Consistent use of shared UI primitives for labels and inputs.
- Focus states and transitions for improved interaction feedback.
GeneratedEmailPanel#
Purpose:
- Displays the generated email with subject and body, supports editing mode, copy-to-clipboard, and text download.
Key behaviors:
- Edit mode toggles a panel with instructions textarea and apply button.
- Uses MarkdownRenderer for rendering email body content.
- Provides action buttons for editing, copying, and downloading.
User feedback:
- Loading states synchronized with mutation status.
- Disabled states during editing to prevent concurrent operations.
Export/download:
- Copies a formatted subject/body string to clipboard.
- Downloads a .txt file containing subject and body.
LoadingOverlay#
Purpose:
- Modal overlay indicating ongoing generation or editing operations with animated loader and customizable messages.
Behavior:
- Conditionally renders based on isGenerating/isEditing flags.
- Dynamically sets title and description depending on operation type.
Styling:
- Uses motion animations for entrance/exit and a pulsing dot indicator.
PageLoader#
Purpose:
- Page-level loader shown during initial component mount.
Behavior:
- Simple overlay with spinner and text until initial load completes.
ResumeSelection#
Purpose:
- Manages three input modes:
- Existing resume: Select from user’s saved resumes with auto-fill of candidate name and predicted field.
- Upload new resume: File picker with preview and accepted formats.
- Custom draft: Paste draft and edit instructions, optionally improve with resume context.
Key behaviors:
- Dynamic mode switching with visual toggle.
- Dropdown selection with resume metadata and upload date.
- File preview for uploaded resumes.
- Optional resume selection for draft editing.
Validation:
- Enforces required selections per mode in the parent page component.
Service layer and types#
Purpose:
- Encapsulate API interactions and define request/response contracts.
Cold-mail.service.ts:
- Exposes methods for retrieving user resumes, generating cold mails, and editing existing emails.
- Uses FormData for multipart requests supporting files and form fields.
Types:
- ColdMailRequest defines required and optional fields for generation/editing.
- ColdMailResponseData standardizes returned subject/body plus optional identifiers.
Backend integration#
Purpose:
- Orchestrate LLM-based cold mail generation and editing via FastAPI endpoints.
Cold_mail.py:
- File-based endpoints for generation and editing accept resume files and form fields.
- Text-based endpoints accept resume text and form fields for alternate workflows.
Prompt Templates:
- cold_mail_gen.py: Structured prompt with example, candidate resume, email details, and formatting instructions.
- cold_mail_editor.py: Similar structure but includes previous email and explicit edit instructions.
Models:
- request.py: Pydantic model validating required fields and optional company URL.
- response.py: Standardized response model with success flag, message, subject, and body.
How it fits together#
graph TB subgraph "Frontend Components" F1["EmailDetailsForm"] F2["GeneratedEmailPanel"] F3["LoadingOverlay"] F4["PageLoader"] F5["ResumeSelection"] F6["page.tsx"] F7["cold-mail.service.ts"] F8["cold-mail.ts"] F9["use-cold-mails.ts"] end subgraph "Backend Services" B1["cold_mail.py"] B2["cold_mail_gen.py"] B3["cold_mail_editor.py"] B4["request.py"] B5["response.py"] end F6 --> F1 F6 --> F2 F6 --> F3 F6 --> F4 F6 --> F5 F6 --> F7 F7 --> B1 B1 --> B2 B1 --> B3 B4 --> B1 B5 --> B1
Email generation workflow#
The workflow begins with user input capture, followed by validation and preparation of FormData. Depending on the selected mode, either the generation or editing endpoint is invoked. The backend applies a structured prompt to produce a personalized email, returning subject and body.
flowchart TD
Start(["User Interaction"]) --> Mode{"Resume Mode?"}
Mode --> |Existing| CheckExisting["Check selectedResumeId"]
Mode --> |Upload| CheckUpload["Check resumeFile or isPreloaded"]
Mode --> |Custom Draft| CheckDraft["Check customDraft and optional resume"]
CheckExisting --> ValidExisting{"Valid?"}
CheckUpload --> ValidUpload{"Valid?"}
CheckDraft --> ValidDraft{"Valid?"}
ValidExisting --> |No| ToastExisting["Show toast: Select a resume"]
ValidUpload --> |No| ToastUpload["Show toast: Upload resume"]
ValidDraft --> |No| ToastDraft["Show toast: Paste draft"]
ValidExisting --> |Yes| Prepare["Prepare FormData"]
ValidUpload --> |Yes| Prepare
ValidDraft --> |Yes| Prepare
Prepare --> ValidateFields["Validate recipient/company/sender fields"]
ValidateFields --> |Invalid| ToastFields["Show toast: Required fields missing"]
ValidateFields --> |Valid| CallAPI["Call generate/edit endpoint"]
CallAPI --> Overlay["Show LoadingOverlay"]
Overlay --> Success{"Success?"}
Success --> |Yes| UpdateUI["Update generatedEmail state"]
Success --> |No| ErrorToast["Show error toast"]
UpdateUI --> End(["Display in GeneratedEmailPanel"])
ErrorToast --> EndTemplate system and personalization logic#
The backend employs structured prompt templates to guide LLM behavior:
- cold_mail_gen.py: Includes an example email, candidate resume, recipient details, key points, additional context, and company insights. Enforces word limits, paragraph structure, tone, and formatting.
- cold_mail_editor.py: Builds upon an existing email and strict edit instructions to refine content while preserving personalization.
Personalization factors:
- Recipient name/designation, company name, sender name, and role/goal.
- Key points to highlight and additional context.
- Optional company URL for research insights.
Integration with backend cold mail APIs#
Frontend service methods:
- getColdMails: Retrieve user cold mail sessions.
- getUserResumes: Fetch user resumes for selection.
- generateColdMail: Submit FormData for cold mail generation.
- editColdMail: Submit FormData for editing an existing email.
Backend endpoints:
- File-based generation and editing accept resume files and form fields.
- Text-based variants accept resume text and form fields for alternate workflows.
Type safety:
- ColdMailRequest enforces required fields and optional company URL.
- ColdMailResponseData standardizes returned subject/body.
Form validation and user feedback#
Validation logic:
- Generates appropriate toasts for missing required fields in each mode.
- Disables the generate button when inputs are invalid.
- Ensures resume selection or upload is present when required.
User feedback:
- Toast notifications for success/error states.
- Loading overlays during generation/editing.
- Page-level loader on initial mount.
Email preview and export/download#
Preview:
- MarkdownRenderer renders email body content with appropriate styling.
- Sticky panel layout ensures visibility during scrolling.
Export/Download:
- Copy to clipboard: Formats subject and body into a single string.
- Download as text: Creates a Blob and triggers a download link.
Dependencies#
graph TB A["page.tsx"] --> B["EmailDetailsForm.tsx"] A --> C["GeneratedEmailPanel.tsx"] A --> D["LoadingOverlay.tsx"] A --> E["PageLoader.tsx"] A --> F["ResumeSelection.tsx"] A --> G["cold-mail.service.ts"] G --> H["cold_mail.py"] H --> I["cold_mail_gen.py"] H --> J["cold_mail_editor.py"] H --> K["request.py"] H --> L["response.py"] A --> M["cold-mail.ts"] A --> N["use-cold-mails.ts"]
Performance#
- Asynchronous operations: Use of mutations and loaders prevents blocking the UI during generation/editing.
- Conditional rendering: Overlays and panels only render when needed, minimizing unnecessary DOM updates.
- File handling: Preview logic reads small portions of text files to avoid heavy computations.
- Toast notifications: Centralized error/success messaging avoids repeated error handling logic.
Troubleshooting#
Common issues:
- Missing required fields: Ensure recipient name, company name, and sender name are filled before generation.
- Resume selection problems: Select an existing resume or upload a valid file; pre-loaded files require re-upload if needed.
- Edit failures: Provide clear edit instructions and ensure an email exists to edit.
- Clipboard errors: Some browsers restrict clipboard access; fall back to manual copy or download.
- Network errors: Inspect service method responses and ensure backend endpoints are reachable.