courrier clean 2$

This commit is contained in:
alma 2025-04-26 20:44:11 +02:00
parent 26e72f4f73
commit ad9999fdd5
8 changed files with 105 additions and 312 deletions

View File

@ -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

View File

@ -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.

View File

@ -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');

View File

@ -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;

View File

@ -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;
}

View File

@ -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(/&nbsp;/g, ' ')
.replace(/&amp;/g, '&')
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&quot;/g, '"');
// Clean up whitespace
return html.replace(/\n\s*\n/g, '\n\n').trim();
}

View File

@ -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: {}
};
}
}

View File

@ -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;
}