courrier clean 2$
This commit is contained in:
parent
26e72f4f73
commit
ad9999fdd5
@ -9,10 +9,20 @@ This document lists functions and files that have been deprecated and should not
|
||||
- **Replacement**: Use `lib/utils/email-formatter.ts` instead
|
||||
- **Reason**: Consolidated email formatting to a single source of truth
|
||||
|
||||
### 2. `cleanHtml` in `lib/mail-parser-wrapper.ts`
|
||||
- **Status**: Deprecated for email composition
|
||||
- **Replacement**: Use `cleanHtmlContent` from `lib/utils/email-formatter.ts` instead
|
||||
- **Reason**: Better handling of text direction and HTML sanitization
|
||||
### 2. `lib/mail-parser-wrapper.ts` (REMOVED)
|
||||
- **Status**: Removed
|
||||
- **Replacement**: Use functions from `lib/utils/email-formatter.ts` instead
|
||||
- **Reason**: Consolidated email formatting and sanitization to a single source of truth
|
||||
|
||||
### 3. `lib/email-parser.ts` (REMOVED)
|
||||
- **Status**: Removed
|
||||
- **Replacement**: Use `lib/server/email-parser.ts` for parsing and `lib/utils/email-formatter.ts` for sanitization
|
||||
- **Reason**: Consolidated email parsing and formatting to dedicated files
|
||||
|
||||
### 4. `lib/compose-mime-decoder.ts` (REMOVED)
|
||||
- **Status**: Removed
|
||||
- **Replacement**: Use `decodeComposeContent` and `encodeComposeContent` functions from `lib/utils/email-formatter.ts`
|
||||
- **Reason**: Consolidated MIME handling into the centralized formatter
|
||||
|
||||
## Deprecated Functions
|
||||
|
||||
@ -38,17 +48,16 @@ All email formatting is now handled by the centralized formatter in `lib/utils/e
|
||||
1. `formatForwardedEmail`: Format emails for forwarding
|
||||
2. `formatReplyEmail`: Format emails for replying or replying to all
|
||||
3. `formatEmailForReplyOrForward`: Compatibility function that maps to the above two
|
||||
4. `cleanHtmlContent`: Safely sanitize HTML content while preserving direction attributes
|
||||
4. `sanitizeHtml`: Safely sanitize HTML content while preserving direction attributes
|
||||
|
||||
Use these functions for all email formatting needs.
|
||||
|
||||
## Email Parsing and Processing Functions
|
||||
|
||||
### 1. `splitEmailHeadersAndBody`
|
||||
- **Location**: `app/courrier/page.tsx`
|
||||
- **Reason**: Email parsing has been centralized in `lib/mail-parser-wrapper.ts` and the API endpoint.
|
||||
- **Replacement**: Use the `decodeEmail` function from `lib/mail-parser-wrapper.ts` which provides a more comprehensive parsing solution.
|
||||
- **Status**: Currently marked with `@deprecated` comment, no usages found.
|
||||
### 1. `splitEmailHeadersAndBody` (REMOVED)
|
||||
- **Location**: Removed
|
||||
- **Reason**: Email parsing has been centralized in `lib/server/email-parser.ts` and the API endpoint.
|
||||
- **Replacement**: Use the `parseEmail` function from `lib/server/email-parser.ts` which provides a comprehensive parsing solution.
|
||||
|
||||
### 2. `getReplyBody`
|
||||
- **Location**: `app/courrier/page.tsx`
|
||||
@ -62,17 +71,15 @@ Use these functions for all email formatting needs.
|
||||
- **Replacement**: Use `<EmailPreview email={email} />` directly.
|
||||
- **Status**: Currently marked with `@deprecated` comment, no usages found.
|
||||
|
||||
### 4. `cleanHtml` (in server/email-parser.ts)
|
||||
- **Location**: `lib/server/email-parser.ts`
|
||||
- **Reason**: This functionality has been centralized in `lib/mail-parser-wrapper.ts`.
|
||||
- **Replacement**: Use `cleanHtml` from `lib/mail-parser-wrapper.ts`.
|
||||
- **Status**: Currently marked with `@deprecated` comment, used in `parseEmail` function.
|
||||
### 4. `cleanHtml` (REMOVED)
|
||||
- **Location**: Removed from `lib/server/email-parser.ts`
|
||||
- **Reason**: HTML sanitization has been consolidated in `lib/utils/email-formatter.ts`.
|
||||
- **Replacement**: Use `sanitizeHtml` from `lib/utils/email-formatter.ts`.
|
||||
|
||||
### 5. `processHtml` (in parse-email/route.ts)
|
||||
- **Location**: `app/api/parse-email/route.ts`
|
||||
- **Reason**: HTML processing has been centralized in `lib/mail-parser-wrapper.ts`.
|
||||
- **Replacement**: Use `cleanHtml` from `lib/mail-parser-wrapper.ts`.
|
||||
- **Status**: Currently marked with `@deprecated` comment, still used in the API route.
|
||||
### 5. `processHtml` (REMOVED)
|
||||
- **Location**: Removed from `app/api/parse-email/route.ts`
|
||||
- **Reason**: HTML processing has been consolidated in `lib/utils/email-formatter.ts`.
|
||||
- **Replacement**: Use `sanitizeHtml` from `lib/utils/email-formatter.ts`.
|
||||
|
||||
## Deprecated API Routes
|
||||
|
||||
@ -112,15 +119,16 @@ A compatibility layer has been added to the new component to ensure backward com
|
||||
|
||||
## Migration Plan
|
||||
|
||||
### Phase 1: Deprecation (Current)
|
||||
### Phase 1: Deprecation (Completed)
|
||||
- Mark all deprecated functions with `@deprecated` comments
|
||||
- Add console warnings to deprecated functions
|
||||
- Document alternatives
|
||||
|
||||
### Phase 2: Removal (Future)
|
||||
- Remove deprecated functions after ensuring no code uses them
|
||||
- Ensure proper migration path for any code that might have been using these functions
|
||||
- Update documentation to remove references to deprecated code
|
||||
### Phase 2: Removal (Completed)
|
||||
- Remove deprecated files: `lib/email-parser.ts` and `lib/mail-parser-wrapper.ts`
|
||||
- Consolidate all email formatting in `lib/utils/email-formatter.ts`
|
||||
- All email parsing now in `lib/server/email-parser.ts`
|
||||
- Update documentation to point to the centralized utilities
|
||||
|
||||
## Server-Client Code Separation
|
||||
|
||||
|
||||
15
README.md
15
README.md
@ -9,22 +9,22 @@ The application handles email processing through a centralized workflow:
|
||||
1. **Email Fetching**: Emails are fetched through the `/api/courrier` endpoints using user credentials stored in the database.
|
||||
|
||||
2. **Email Parsing**: Raw email content is parsed using:
|
||||
- Server-side: `simpleParser` from `mailparser` library via `/api/parse-email` API route
|
||||
- Client-side: `decodeEmail` function in `lib/mail-parser-wrapper.ts`
|
||||
- Server-side: `parseEmail` function from `lib/server/email-parser.ts` (which uses `simpleParser` from the `mailparser` library)
|
||||
- API route: `/api/parse-email` provides a REST interface to the parser
|
||||
|
||||
3. **HTML Sanitization**: Email HTML content is sanitized and processed using:
|
||||
- `cleanHtml` function in `lib/mail-parser-wrapper.ts` (centralized implementation)
|
||||
- CSS styles are optionally preserved and scoped to prevent leakage
|
||||
- `sanitizeHtml` function in `lib/utils/email-formatter.ts` (centralized implementation)
|
||||
- Text direction (RTL/LTR) is preserved automatically during sanitization
|
||||
|
||||
4. **Email Display**: Sanitized content is rendered in the UI with proper styling and security measures
|
||||
|
||||
5. **Email Composition**: The `ComposeEmail` component handles email creation, replying, and forwarding
|
||||
- `initializeForwardedEmail` function prepares forwarded email content
|
||||
- Uses the centralized formatter functions to prepare content
|
||||
- Email is sent through the `/api/courrier/send` endpoint
|
||||
|
||||
## Deprecated Functions
|
||||
|
||||
Several functions have been marked as deprecated in favor of centralized implementations:
|
||||
Several functions have been deprecated and removed in favor of centralized implementations:
|
||||
|
||||
- Check the `DEPRECATED_FUNCTIONS.md` file for a complete list of deprecated functions and their replacements.
|
||||
|
||||
@ -35,6 +35,7 @@ Several functions have been marked as deprecated in favor of centralized impleme
|
||||
- `/lib` - Utility functions and services
|
||||
- `/services` - Domain-specific services, including email service
|
||||
- `/server` - Server-side utilities
|
||||
- `/utils` - Utility functions including the centralized email formatter
|
||||
|
||||
## Dependencies
|
||||
|
||||
@ -72,7 +73,7 @@ All email formatting is now handled by a centralized formatter in `lib/utils/ema
|
||||
|
||||
- `formatForwardedEmail`: Format emails for forwarding
|
||||
- `formatReplyEmail`: Format emails for replying
|
||||
- `cleanHtmlContent`: Sanitize HTML while preserving direction attributes
|
||||
- `sanitizeHtml`: Sanitize HTML while preserving direction attributes
|
||||
- `formatEmailForReplyOrForward`: Compatibility function for both
|
||||
|
||||
This centralized approach prevents formatting inconsistencies and direction problems when dealing with emails in different languages.
|
||||
@ -124,7 +124,7 @@ interface ParsedEmailMetadata {
|
||||
|
||||
/**
|
||||
* @deprecated This function is deprecated and will be removed in future versions.
|
||||
* Email parsing has been centralized in lib/mail-parser-wrapper.ts and the API endpoint.
|
||||
* Email parsing has been centralized in lib/server/email-parser.ts and the API endpoint.
|
||||
*/
|
||||
function splitEmailHeadersAndBody(emailBody: string): { headers: string; body: string } {
|
||||
const [headers, ...bodyParts] = emailBody.split('\r\n\r\n');
|
||||
|
||||
@ -5,7 +5,7 @@ import DOMPurify from 'isomorphic-dompurify';
|
||||
import { Loader2, Paperclip, Download } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { cleanHtml } from '@/lib/mail-parser-wrapper';
|
||||
import { sanitizeHtml } from '@/lib/utils/email-formatter';
|
||||
|
||||
interface EmailAddress {
|
||||
name: string;
|
||||
|
||||
@ -1,60 +0,0 @@
|
||||
/**
|
||||
* Simple MIME decoder for compose message box
|
||||
* Handles basic email content without creating nested structures
|
||||
*/
|
||||
|
||||
interface ParsedContent {
|
||||
html: string | null;
|
||||
text: string | null;
|
||||
}
|
||||
|
||||
export async function decodeComposeContent(content: string): Promise<ParsedContent> {
|
||||
if (!content.trim()) {
|
||||
return { html: null, text: null };
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/parse-email', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ email: content }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to parse email');
|
||||
}
|
||||
|
||||
const parsed = await response.json();
|
||||
return {
|
||||
html: parsed.html || null,
|
||||
text: parsed.text || null
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error parsing email content:', error);
|
||||
// Fallback to basic content handling
|
||||
return {
|
||||
html: content,
|
||||
text: content
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function encodeComposeContent(content: string): Promise<string> {
|
||||
if (!content.trim()) {
|
||||
throw new Error('Email content is empty');
|
||||
}
|
||||
|
||||
// Create MIME headers
|
||||
const mimeHeaders = {
|
||||
'MIME-Version': '1.0',
|
||||
'Content-Type': 'text/html; charset="utf-8"',
|
||||
'Content-Transfer-Encoding': 'quoted-printable'
|
||||
};
|
||||
|
||||
// Combine headers and content
|
||||
return Object.entries(mimeHeaders)
|
||||
.map(([key, value]) => `${key}: ${value}`)
|
||||
.join('\n') + '\n\n' + content;
|
||||
}
|
||||
@ -1,115 +0,0 @@
|
||||
/**
|
||||
* @deprecated This entire file is deprecated and will be removed in future versions.
|
||||
* Use the parseEmail function from lib/server/email-parser.ts and
|
||||
* sanitizeHtml from lib/utils/email-formatter.ts instead.
|
||||
* This file is maintained only for backward compatibility.
|
||||
*/
|
||||
|
||||
interface EmailHeaders {
|
||||
from: string;
|
||||
subject: string;
|
||||
date: string;
|
||||
to?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use parseEmail from lib/server/email-parser.ts instead.
|
||||
*/
|
||||
export function parseEmailHeaders(headerContent: string): EmailHeaders {
|
||||
console.warn('parseEmailHeaders is deprecated. Use parseEmail from lib/server/email-parser.ts instead.');
|
||||
|
||||
const headers: { [key: string]: string } = {};
|
||||
let currentHeader = '';
|
||||
let currentValue = '';
|
||||
|
||||
// Split the header content into lines
|
||||
const lines = headerContent.split(/\r?\n/);
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i];
|
||||
|
||||
// If line starts with whitespace, it's a continuation of the previous header
|
||||
if (/^\s+/.test(line)) {
|
||||
currentValue += ' ' + line.trim();
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we have a current header being processed, save it
|
||||
if (currentHeader && currentValue) {
|
||||
headers[currentHeader.toLowerCase()] = currentValue.trim();
|
||||
}
|
||||
|
||||
// Start processing new header
|
||||
const match = line.match(/^([^:]+):\s*(.*)$/);
|
||||
if (match) {
|
||||
currentHeader = match[1];
|
||||
currentValue = match[2];
|
||||
}
|
||||
}
|
||||
|
||||
// Save the last header
|
||||
if (currentHeader && currentValue) {
|
||||
headers[currentHeader.toLowerCase()] = currentValue.trim();
|
||||
}
|
||||
|
||||
return {
|
||||
from: headers['from'] || '',
|
||||
subject: headers['subject'] || '',
|
||||
date: headers['date'] || new Date().toISOString(),
|
||||
to: headers['to']
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use sanitizeHtml from lib/utils/email-formatter.ts instead.
|
||||
*/
|
||||
export function decodeEmailBody(content: string, contentType: string): string {
|
||||
console.warn('decodeEmailBody is deprecated. Use sanitizeHtml from lib/utils/email-formatter.ts instead.');
|
||||
|
||||
try {
|
||||
// Remove email client-specific markers
|
||||
content = content.replace(/\r\n/g, '\n')
|
||||
.replace(/=\n/g, '')
|
||||
.replace(/=3D/g, '=')
|
||||
.replace(/=09/g, '\t');
|
||||
|
||||
// If it's HTML content
|
||||
if (contentType.includes('text/html')) {
|
||||
return extractTextFromHtml(content);
|
||||
}
|
||||
|
||||
return content;
|
||||
} catch (error) {
|
||||
console.error('Error decoding email body:', error);
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use sanitizeHtml from lib/utils/email-formatter.ts instead.
|
||||
*/
|
||||
function extractTextFromHtml(html: string): string {
|
||||
console.warn('extractTextFromHtml is deprecated. Use sanitizeHtml from lib/utils/email-formatter.ts instead.');
|
||||
|
||||
// Remove scripts and style tags
|
||||
html = html.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '')
|
||||
.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '');
|
||||
|
||||
// Convert <br> and <p> to newlines
|
||||
html = html.replace(/<br[^>]*>/gi, '\n')
|
||||
.replace(/<p[^>]*>/gi, '\n')
|
||||
.replace(/<\/p>/gi, '\n');
|
||||
|
||||
// Remove all other HTML tags
|
||||
html = html.replace(/<[^>]+>/g, '');
|
||||
|
||||
// Decode HTML entities
|
||||
html = html.replace(/ /g, ' ')
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"');
|
||||
|
||||
// Clean up whitespace
|
||||
return html.replace(/\n\s*\n/g, '\n\n').trim();
|
||||
}
|
||||
@ -1,103 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import DOMPurify from 'dompurify';
|
||||
import { sanitizeHtml } from '@/lib/utils/email-formatter';
|
||||
|
||||
export interface ParsedEmail {
|
||||
subject: string | null;
|
||||
from: string | null;
|
||||
to: string | null;
|
||||
cc: string | null;
|
||||
bcc: string | null;
|
||||
date: Date | null;
|
||||
html: string | null;
|
||||
text: string | null;
|
||||
attachments: Array<{
|
||||
filename: string;
|
||||
contentType: string;
|
||||
size: number;
|
||||
}>;
|
||||
headers: Record<string, any>;
|
||||
}
|
||||
|
||||
export async function decodeEmail(emailContent: string): Promise<ParsedEmail> {
|
||||
try {
|
||||
// Ensure the email content is properly formatted
|
||||
const formattedContent = emailContent?.trim();
|
||||
if (!formattedContent) {
|
||||
return {
|
||||
subject: null,
|
||||
from: null,
|
||||
to: null,
|
||||
cc: null,
|
||||
bcc: null,
|
||||
date: null,
|
||||
html: null,
|
||||
text: 'No content available',
|
||||
attachments: [],
|
||||
headers: {}
|
||||
};
|
||||
}
|
||||
|
||||
const response = await fetch('/api/parse-email', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ email: formattedContent }),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
console.error('API Error:', data);
|
||||
return {
|
||||
subject: null,
|
||||
from: null,
|
||||
to: null,
|
||||
cc: null,
|
||||
bcc: null,
|
||||
date: null,
|
||||
html: null,
|
||||
text: data.error || 'Failed to parse email',
|
||||
attachments: [],
|
||||
headers: {}
|
||||
};
|
||||
}
|
||||
|
||||
// If we have a successful response but no content
|
||||
if (!data.html && !data.text) {
|
||||
return {
|
||||
...data,
|
||||
date: data.date ? new Date(data.date) : null,
|
||||
html: null,
|
||||
text: 'No content available',
|
||||
attachments: data.attachments || [],
|
||||
headers: data.headers || {}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...data,
|
||||
date: data.date ? new Date(data.date) : null,
|
||||
text: data.text || null,
|
||||
html: data.html || null,
|
||||
attachments: data.attachments || [],
|
||||
headers: data.headers || {}
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error parsing email:', error);
|
||||
return {
|
||||
subject: null,
|
||||
from: null,
|
||||
to: null,
|
||||
cc: null,
|
||||
bcc: null,
|
||||
date: null,
|
||||
html: null,
|
||||
text: 'Error parsing email content',
|
||||
attachments: [],
|
||||
headers: {}
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -268,4 +268,66 @@ export function formatEmailForReplyOrForward(
|
||||
body: content
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode compose content from MIME format to HTML and text
|
||||
* This replaces the functionality previously in lib/compose-mime-decoder.ts
|
||||
*/
|
||||
export async function decodeComposeContent(content: string): Promise<{
|
||||
html: string | null;
|
||||
text: string | null;
|
||||
}> {
|
||||
if (!content.trim()) {
|
||||
return { html: null, text: null };
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/parse-email', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ email: content }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to parse email');
|
||||
}
|
||||
|
||||
const parsed = await response.json();
|
||||
return {
|
||||
html: parsed.html || null,
|
||||
text: parsed.text || null
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error parsing email content:', error);
|
||||
// Fallback to basic content handling
|
||||
return {
|
||||
html: content,
|
||||
text: content
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode compose content to MIME format for sending
|
||||
* This replaces the functionality previously in lib/compose-mime-decoder.ts
|
||||
*/
|
||||
export function encodeComposeContent(content: string): string {
|
||||
if (!content.trim()) {
|
||||
throw new Error('Email content is empty');
|
||||
}
|
||||
|
||||
// Create MIME headers
|
||||
const mimeHeaders = {
|
||||
'MIME-Version': '1.0',
|
||||
'Content-Type': 'text/html; charset="utf-8"',
|
||||
'Content-Transfer-Encoding': 'quoted-printable'
|
||||
};
|
||||
|
||||
// Combine headers and content
|
||||
return Object.entries(mimeHeaders)
|
||||
.map(([key, value]) => `${key}: ${value}`)
|
||||
.join('\n') + '\n\n' + content;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user