courrier clean 2$
This commit is contained in:
parent
4c9fcdeb29
commit
afc7f64027
@ -1,6 +1,46 @@
|
||||
# Deprecated Functions and Code
|
||||
# Deprecated Functions and Files
|
||||
|
||||
This document tracks functions that have been marked as deprecated and should be removed in future releases.
|
||||
This document lists functions and files that have been deprecated and should not be used in new code.
|
||||
|
||||
## Deprecated Files
|
||||
|
||||
### 1. `lib/email-formatter.ts` (REMOVED)
|
||||
- **Status**: Removed
|
||||
- **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
|
||||
|
||||
## Deprecated Functions
|
||||
|
||||
### 1. `formatEmailForReplyOrForward` in `lib/services/email-service.ts` (REMOVED)
|
||||
- **Status**: Removed
|
||||
- **Replacement**: Use `formatEmailForReplyOrForward` from `lib/utils/email-formatter.ts`
|
||||
- **Reason**: Consolidated email formatting to a single source of truth
|
||||
|
||||
### 2. `formatSubject` in `lib/services/email-service.ts` (REMOVED)
|
||||
- **Status**: Removed
|
||||
- **Replacement**: None specific, handled by centralized formatter
|
||||
- **Reason**: Internal function of the email formatter
|
||||
|
||||
### 3. `createQuoteHeader` in `lib/services/email-service.ts` (REMOVED)
|
||||
- **Status**: Removed
|
||||
- **Replacement**: None specific, handled by centralized formatter
|
||||
- **Reason**: Internal function of the email formatter
|
||||
|
||||
## Centralized Email Formatting
|
||||
|
||||
All email formatting is now handled by the centralized formatter in `lib/utils/email-formatter.ts`. This file contains:
|
||||
|
||||
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
|
||||
|
||||
Use these functions for all email formatting needs.
|
||||
|
||||
## Email Parsing and Processing Functions
|
||||
|
||||
|
||||
21
README.md
21
README.md
@ -56,4 +56,23 @@ npm run dev
|
||||
|
||||
# Build for production
|
||||
npm run build
|
||||
```
|
||||
```
|
||||
|
||||
# Email Formatting
|
||||
|
||||
## Centralized Email Formatter
|
||||
|
||||
All email formatting is now handled by a centralized formatter in `lib/utils/email-formatter.ts`. This ensures consistent handling of:
|
||||
|
||||
- Text direction (RTL/LTR)
|
||||
- HTML sanitization
|
||||
- Content formatting for forwards and replies
|
||||
|
||||
### Key Functions
|
||||
|
||||
- `formatForwardedEmail`: Format emails for forwarding
|
||||
- `formatReplyEmail`: Format emails for replying
|
||||
- `cleanHtmlContent`: 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.
|
||||
@ -1,6 +1,7 @@
|
||||
'use server';
|
||||
|
||||
import { getEmails, formatEmailForReplyOrForward, EmailMessage, EmailAddress } from '@/lib/services/email-service';
|
||||
import { getEmails, EmailMessage, EmailAddress } from '@/lib/services/email-service';
|
||||
import { formatEmailForReplyOrForward } from '@/lib/utils/email-formatter';
|
||||
|
||||
/**
|
||||
* Server action to fetch emails
|
||||
@ -20,6 +21,7 @@ export async function fetchEmails(userId: string, folder = 'INBOX', page = 1, pe
|
||||
|
||||
/**
|
||||
* Server action to format email for reply or forward operations
|
||||
* Uses the centralized email formatter
|
||||
*/
|
||||
export async function formatEmailServerSide(
|
||||
email: {
|
||||
@ -71,7 +73,7 @@ export async function formatEmailServerSide(
|
||||
contentFetched: true
|
||||
};
|
||||
|
||||
// Use the server-side formatter
|
||||
// Use the centralized formatter
|
||||
const formatted = formatEmailForReplyOrForward(serverEmail, type);
|
||||
|
||||
return {
|
||||
|
||||
@ -1,225 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import DOMPurify from 'dompurify';
|
||||
|
||||
/**
|
||||
* Client-side utilities for formatting email content
|
||||
* This file contains functions for formatting email content in the browser
|
||||
* without any server dependencies.
|
||||
*/
|
||||
|
||||
export interface EmailAddress {
|
||||
address: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export interface FormattedEmail {
|
||||
subject: string;
|
||||
to?: EmailAddress[];
|
||||
cc?: EmailAddress[];
|
||||
bcc?: EmailAddress[];
|
||||
body: string;
|
||||
}
|
||||
|
||||
export interface EmailMessageForFormatting {
|
||||
subject?: string;
|
||||
from?: EmailAddress | EmailAddress[];
|
||||
to?: EmailAddress | EmailAddress[];
|
||||
date?: Date | string;
|
||||
html?: string;
|
||||
text?: string;
|
||||
cc?: EmailAddress | EmailAddress[];
|
||||
bcc?: EmailAddress | EmailAddress[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Format an email for replying or forwarding
|
||||
* Client-side friendly version that doesn't depend on server modules
|
||||
*/
|
||||
export function formatEmailForReply(
|
||||
originalEmail: EmailMessageForFormatting,
|
||||
type: 'reply' | 'replyAll' | 'forward' = 'reply'
|
||||
): FormattedEmail {
|
||||
// Format the subject with Re: or Fwd: prefix
|
||||
const subject = formatSubject(originalEmail.subject || '', type);
|
||||
|
||||
// Initialize recipients based on reply type
|
||||
let to: EmailAddress[] = [];
|
||||
let cc: EmailAddress[] = [];
|
||||
|
||||
if (type === 'reply' && originalEmail.from) {
|
||||
to = Array.isArray(originalEmail.from) ? originalEmail.from : [originalEmail.from];
|
||||
} else if (type === 'replyAll') {
|
||||
// To: original sender
|
||||
if (originalEmail.from) {
|
||||
to = Array.isArray(originalEmail.from) ? originalEmail.from : [originalEmail.from];
|
||||
}
|
||||
|
||||
// CC: all other recipients
|
||||
if (originalEmail.to) {
|
||||
cc = Array.isArray(originalEmail.to) ? originalEmail.to : [originalEmail.to];
|
||||
}
|
||||
|
||||
if (originalEmail.cc) {
|
||||
const existingCc = Array.isArray(originalEmail.cc) ? originalEmail.cc : [originalEmail.cc];
|
||||
cc = [...cc, ...existingCc];
|
||||
}
|
||||
|
||||
// Remove duplicates and self from CC (would need user's email here)
|
||||
// This is simplified - in a real app you'd filter out the current user
|
||||
cc = cc.filter((value, index, self) =>
|
||||
index === self.findIndex((t) => t.address === value.address)
|
||||
);
|
||||
}
|
||||
|
||||
// Create the quoted content with header
|
||||
const quoteHeader = createQuoteHeader(originalEmail);
|
||||
|
||||
// Get the original content, preferring HTML over plain text
|
||||
let originalContent = '';
|
||||
if (originalEmail.html) {
|
||||
// Sanitize any potentially unsafe HTML
|
||||
originalContent = DOMPurify.sanitize(originalEmail.html);
|
||||
} else if (originalEmail.text) {
|
||||
// Convert text to HTML by replacing newlines with br tags
|
||||
originalContent = originalEmail.text.replace(/\n/g, '<br>');
|
||||
}
|
||||
|
||||
// Combine the header with the original content, ensuring proper direction
|
||||
const body = `
|
||||
<div dir="ltr" style="text-align: left;">
|
||||
<br>
|
||||
<blockquote style="margin: 0 0 0 0.8ex; border-left: 1px solid #ccc; padding-left: 1ex;">
|
||||
${quoteHeader}
|
||||
<div style="direction: ltr; text-align: left;">${originalContent || 'No content available'}</div>
|
||||
</blockquote>
|
||||
</div>
|
||||
`;
|
||||
|
||||
return {
|
||||
subject,
|
||||
to,
|
||||
cc,
|
||||
body
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Format email subject with appropriate prefix
|
||||
*/
|
||||
export function formatSubject(
|
||||
originalSubject: string,
|
||||
type: 'reply' | 'replyAll' | 'forward'
|
||||
): string {
|
||||
// Trim whitespace
|
||||
let subject = originalSubject.trim();
|
||||
|
||||
// Remove existing prefixes to avoid duplication
|
||||
subject = subject.replace(/^(Re|Fwd):\s*/gi, '');
|
||||
|
||||
// Add appropriate prefix based on action type
|
||||
if (type === 'forward') {
|
||||
return `Fwd: ${subject}`;
|
||||
} else {
|
||||
return `Re: ${subject}`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a formatted quote header with sender and date information
|
||||
*/
|
||||
export function createQuoteHeader(email: EmailMessageForFormatting): string {
|
||||
let fromName = 'Unknown Sender';
|
||||
let fromEmail = '';
|
||||
|
||||
// Extract sender information
|
||||
if (email.from) {
|
||||
if (Array.isArray(email.from)) {
|
||||
fromName = email.from[0].name || email.from[0].address;
|
||||
fromEmail = email.from[0].address;
|
||||
} else {
|
||||
fromName = email.from.name || email.from.address;
|
||||
fromEmail = email.from.address;
|
||||
}
|
||||
}
|
||||
|
||||
// Format the date
|
||||
let dateFormatted = '';
|
||||
if (email.date) {
|
||||
const date = typeof email.date === 'string' ? new Date(email.date) : email.date;
|
||||
|
||||
// Check if the date is valid
|
||||
if (!isNaN(date.getTime())) {
|
||||
dateFormatted = date.toLocaleString('en-US', {
|
||||
weekday: 'short',
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Generate recipients string
|
||||
let recipients = '';
|
||||
if (email.to) {
|
||||
if (Array.isArray(email.to)) {
|
||||
recipients = email.to.map(r => r.name || r.address).join(', ');
|
||||
} else {
|
||||
recipients = email.to.name || email.to.address;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the header HTML with explicit LTR direction
|
||||
return `
|
||||
<div style="margin-bottom: 10px; color: #555; font-size: 0.9em; direction: ltr; text-align: left;">
|
||||
<div><strong>From:</strong> ${fromName} <${fromEmail}></div>
|
||||
${dateFormatted ? `<div><strong>Date:</strong> ${dateFormatted}</div>` : ''}
|
||||
<div><strong>Subject:</strong> ${email.subject || 'No Subject'}</div>
|
||||
<div><strong>To:</strong> ${recipients || 'No Recipients'}</div>
|
||||
${email.cc ? `<div><strong>Cc:</strong> ${Array.isArray(email.cc) ?
|
||||
email.cc.map(r => r.name || r.address).join(', ') :
|
||||
(email.cc.name || email.cc.address)}</div>` : ''}
|
||||
</div>
|
||||
<hr style="border: none; border-top: 1px solid #ddd; margin: 10px 0;">
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format an email for forwarding
|
||||
*/
|
||||
export function formatEmailForForward(email: EmailMessageForFormatting): FormattedEmail {
|
||||
// Format the subject with Fwd: prefix
|
||||
const subject = formatSubject(email.subject || '', 'forward');
|
||||
|
||||
// Create the forward header
|
||||
const forwardHeader = createQuoteHeader(email);
|
||||
|
||||
// Get the original content, preferring HTML over plain text
|
||||
let originalContent = '';
|
||||
if (email.html) {
|
||||
// Sanitize any potentially unsafe HTML
|
||||
originalContent = DOMPurify.sanitize(email.html);
|
||||
} else if (email.text) {
|
||||
// Convert text to HTML by replacing newlines with br tags
|
||||
originalContent = email.text.replace(/\n/g, '<br>');
|
||||
}
|
||||
|
||||
// Combine the header with the original content, ensuring proper direction
|
||||
const body = `
|
||||
<div dir="ltr" style="text-align: left;">
|
||||
<br>
|
||||
<div style="border-left: 1px solid #ccc; padding-left: 1ex; margin-left: 0.8ex; direction: ltr; text-align: left;">
|
||||
<div style="font-weight: bold; margin-bottom: 10px; direction: ltr; text-align: left;">---------- Forwarded message ---------</div>
|
||||
${forwardHeader}
|
||||
<div style="direction: ltr; text-align: left;">${originalContent || '<div style="padding: 10px; text-align: center; background-color: #f8f8f8; border: 1px dashed #ccc; margin: 10px 0;">No content available</div>'}</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
return {
|
||||
subject,
|
||||
body
|
||||
};
|
||||
}
|
||||
@ -628,138 +628,5 @@ export async function testEmailConnection(credentials: EmailCredentials): Promis
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format email for reply/forward
|
||||
*/
|
||||
export async function formatEmailForReplyOrForward(
|
||||
email: EmailMessage,
|
||||
type: 'reply' | 'reply-all' | 'forward'
|
||||
): Promise<{
|
||||
to: string;
|
||||
cc?: string;
|
||||
subject: string;
|
||||
body: string;
|
||||
}> {
|
||||
// Format the subject with Re: or Fwd: prefix
|
||||
const subject = await formatSubject(email.subject, type);
|
||||
|
||||
// Create the email quote with proper formatting
|
||||
const quoteHeader = await createQuoteHeader(email);
|
||||
const quotedContent = email.html || email.text || '';
|
||||
|
||||
// Format recipients
|
||||
let to = '';
|
||||
let cc = '';
|
||||
|
||||
if (type === 'reply') {
|
||||
// Reply to sender only
|
||||
to = email.from.map(addr => `${addr.name} <${addr.address}>`).join(', ');
|
||||
} else if (type === 'reply-all') {
|
||||
// Reply to sender and all recipients
|
||||
to = email.from.map(addr => `${addr.name} <${addr.address}>`).join(', ');
|
||||
|
||||
// Add all original recipients to CC, except ourselves
|
||||
const allRecipients = [
|
||||
...(email.to || []),
|
||||
...(email.cc || [])
|
||||
];
|
||||
|
||||
cc = allRecipients
|
||||
.map(addr => `${addr.name} <${addr.address}>`)
|
||||
.join(', ');
|
||||
} else if (type === 'forward') {
|
||||
// Forward case doesn't need to set recipients
|
||||
to = '';
|
||||
|
||||
// Instead, we format the content differently
|
||||
const formattedDate = email.date ? new Date(email.date).toLocaleString() : '';
|
||||
const fromText = email.from.map(f => f.name ? `${f.name} <${f.address}>` : f.address).join(', ');
|
||||
const toText = email.to.map(t => t.name ? `${t.name} <${t.address}>` : t.address).join(', ');
|
||||
|
||||
// Return specialized body for forward with improved styling
|
||||
return {
|
||||
to: '',
|
||||
subject,
|
||||
body: `
|
||||
<div class="forwarded-message" style="margin-top: 20px;">
|
||||
<div style="background-color: #f5f5f5; border-left: 3px solid #ddd; padding: 12px; margin-bottom: 15px; border-radius: 4px;">
|
||||
<p style="margin: 0 0 8px 0; font-weight: 500; color: #555; font-size: 14px;">---------- Forwarded message ---------</p>
|
||||
<p style="margin: 0 0 6px 0; font-size: 13px;"><span style="font-weight: 600; color: #444;">From:</span> ${fromText}</p>
|
||||
<p style="margin: 0 0 6px 0; font-size: 13px;"><span style="font-weight: 600; color: #444;">Date:</span> ${formattedDate}</p>
|
||||
<p style="margin: 0 0 6px 0; font-size: 13px;"><span style="font-weight: 600; color: #444;">Subject:</span> ${email.subject || ''}</p>
|
||||
<p style="margin: 0 0 6px 0; font-size: 13px;"><span style="font-weight: 600; color: #444;">To:</span> ${toText}</p>
|
||||
</div>
|
||||
<div class="forwarded-content" style="border-left: 2px solid #ddd; padding-left: 15px; color: #333;">
|
||||
${email.html || email.text ? (email.html || `<pre style="white-space: pre-wrap; font-family: inherit; margin: 0;">${email.text || ''}</pre>`) : '<p>No content available</p>'}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
};
|
||||
}
|
||||
|
||||
// Format the email body with improved quote styling for replies
|
||||
const body = `
|
||||
<div class="reply-body">
|
||||
<br/>
|
||||
<div class="quote-header" style="color: #555; font-size: 13px; margin: 20px 0 10px 0;">${quoteHeader}</div>
|
||||
<blockquote style="margin: 0; padding: 10px 0 10px 15px; border-left: 3px solid #ddd; color: #555; background-color: #f8f8f8; border-radius: 4px;">
|
||||
<div class="quoted-content" style="font-size: 13px;">
|
||||
${quotedContent}
|
||||
</div>
|
||||
</blockquote>
|
||||
</div>`;
|
||||
|
||||
return {
|
||||
to,
|
||||
cc: cc || undefined,
|
||||
subject,
|
||||
body
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Format subject with appropriate prefix (Re:, Fwd:)
|
||||
*/
|
||||
export async function formatSubject(subject: string, type: 'reply' | 'reply-all' | 'forward'): Promise<string> {
|
||||
// Clean up any existing prefixes
|
||||
let cleanSubject = subject
|
||||
.replace(/^(Re|Fwd|FW|Forward):\s*/i, '')
|
||||
.trim();
|
||||
|
||||
// Add appropriate prefix
|
||||
if (type === 'reply' || type === 'reply-all') {
|
||||
if (!subject.match(/^Re:/i)) {
|
||||
return `Re: ${cleanSubject}`;
|
||||
}
|
||||
} else if (type === 'forward') {
|
||||
if (!subject.match(/^(Fwd|FW|Forward):/i)) {
|
||||
return `Fwd: ${cleanSubject}`;
|
||||
}
|
||||
}
|
||||
|
||||
return subject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a quote header for reply/forward
|
||||
*/
|
||||
export async function createQuoteHeader(email: EmailMessage): Promise<string> {
|
||||
// Format the date
|
||||
const date = new Date(email.date);
|
||||
const formattedDate = date.toLocaleString('en-US', {
|
||||
weekday: 'short',
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
});
|
||||
|
||||
// Format the sender
|
||||
const sender = email.from[0];
|
||||
const fromText = sender?.name
|
||||
? `${sender.name} <${sender.address}>`
|
||||
: sender?.address || 'Unknown sender';
|
||||
|
||||
return `<div style="font-weight: 500;">On ${formattedDate}, ${fromText} wrote:</div>`;
|
||||
}
|
||||
// Email formatting functions have been moved to lib/utils/email-formatter.ts
|
||||
// Use those functions instead of the ones previously defined here
|
||||
Loading…
Reference in New Issue
Block a user