Neah version mail remove mail correction 2 ??

This commit is contained in:
alma 2025-04-16 20:37:03 +02:00
parent f9ebf07855
commit 0de53ddb6e
2 changed files with 261 additions and 71 deletions

View File

@ -1,5 +1,32 @@
import { NextResponse } from 'next/server'; import { NextResponse } from 'next/server';
import { getImapClient } from '@/lib/imap'; import { cookies } from 'next/headers';
import Imap from 'imap';
interface StoredCredentials {
email: string;
password: string;
host: string;
port: number;
}
function getStoredCredentials(): StoredCredentials | null {
const cookieStore = cookies();
const credentialsCookie = cookieStore.get('imap_credentials');
if (!credentialsCookie?.value) {
return null;
}
try {
const credentials = JSON.parse(credentialsCookie.value);
if (!credentials.email || !credentials.password || !credentials.host || !credentials.port) {
return null;
}
return credentials;
} catch (error) {
return null;
}
}
export async function POST(request: Request) { export async function POST(request: Request) {
try { try {
@ -16,53 +43,125 @@ export async function POST(request: Request) {
const url = new URL(request.url); const url = new URL(request.url);
const folder = url.searchParams.get('folder') || 'INBOX'; const folder = url.searchParams.get('folder') || 'INBOX';
// Get the IMAP client using the same method as the mail endpoint // Get stored credentials
const imap = await getImapClient(); const credentials = getStoredCredentials();
if (!imap) { if (!credentials) {
return NextResponse.json( return NextResponse.json(
{ error: 'Failed to connect to mail server' }, { error: 'No stored credentials found' },
{ status: 500 } { status: 401 }
); );
} }
// Convert string IDs to numbers return new Promise((resolve) => {
const numericIds = emailIds.map(id => parseInt(id, 10)); const imap = new Imap({
user: credentials.email,
// Get mailbox lock for the current folder password: credentials.password,
const lock = await imap.getMailboxLock(folder); host: credentials.host,
port: credentials.port,
try { tls: true,
// Fetch messages to get their UIDs tlsOptions: { rejectUnauthorized: false },
const messages = await imap.fetch({ authTimeout: 30000,
seq: numericIds.map(id => id.toString()), connTimeout: 30000
uid: true,
envelope: true
}); });
// Process each message based on the action const timeout = setTimeout(() => {
for await (const message of messages) { console.error('IMAP connection timeout');
if (!message.uid) continue; imap.end();
resolve(NextResponse.json({ error: 'Connection timeout' }));
}, 30000);
switch (action) { imap.once('error', (err: Error) => {
case 'delete': console.error('IMAP error:', err);
await imap.messageMove(message.uid, 'Trash'); clearTimeout(timeout);
break; resolve(NextResponse.json({ error: 'IMAP connection error' }));
case 'mark-read': });
await imap.messageFlagsAdd(message.uid, ['\\Seen'], { uid: true });
break;
case 'mark-unread':
await imap.messageFlagsRemove(message.uid, ['\\Seen'], { uid: true });
break;
case 'archive':
await imap.messageMove(message.uid, 'Archive');
break;
}
}
return NextResponse.json({ success: true }); imap.once('ready', () => {
} finally { imap.openBox(folder, false, (err, box) => {
lock.release(); if (err) {
} console.error(`Error opening box ${folder}:`, err);
clearTimeout(timeout);
imap.end();
resolve(NextResponse.json({ error: `Failed to open folder ${folder}` }));
return;
}
// Convert string IDs to numbers
const numericIds = emailIds.map(id => parseInt(id, 10));
// Process each email
let processedCount = 0;
const totalEmails = numericIds.length;
const processNextEmail = (index: number) => {
if (index >= totalEmails) {
clearTimeout(timeout);
imap.end();
resolve(NextResponse.json({ success: true }));
return;
}
const id = numericIds[index];
const fetch = imap.fetch(id.toString(), {
bodies: '',
struct: true
});
fetch.on('message', (msg) => {
msg.once('attributes', (attrs) => {
const uid = attrs.uid;
if (!uid) {
processedCount++;
processNextEmail(index + 1);
return;
}
switch (action) {
case 'delete':
imap.move(uid, 'Trash', (err) => {
if (err) console.error('Error moving to trash:', err);
processedCount++;
processNextEmail(index + 1);
});
break;
case 'mark-read':
imap.addFlags(uid, ['\\Seen'], (err) => {
if (err) console.error('Error marking as read:', err);
processedCount++;
processNextEmail(index + 1);
});
break;
case 'mark-unread':
imap.removeFlags(uid, ['\\Seen'], (err) => {
if (err) console.error('Error marking as unread:', err);
processedCount++;
processNextEmail(index + 1);
});
break;
case 'archive':
imap.move(uid, 'Archive', (err) => {
if (err) console.error('Error moving to archive:', err);
processedCount++;
processNextEmail(index + 1);
});
break;
}
});
});
fetch.on('error', (err) => {
console.error('Error fetching email:', err);
processedCount++;
processNextEmail(index + 1);
});
};
processNextEmail(0);
});
});
imap.connect();
});
} catch (error) { } catch (error) {
console.error('Error in bulk actions:', error); console.error('Error in bulk actions:', error);
return NextResponse.json( return NextResponse.json(

View File

@ -1,5 +1,32 @@
import { NextResponse } from 'next/server'; import { NextResponse } from 'next/server';
import { getImapClient } from '@/lib/imap'; import { cookies } from 'next/headers';
import Imap from 'imap';
interface StoredCredentials {
email: string;
password: string;
host: string;
port: number;
}
function getStoredCredentials(): StoredCredentials | null {
const cookieStore = cookies();
const credentialsCookie = cookieStore.get('imap_credentials');
if (!credentialsCookie?.value) {
return null;
}
try {
const credentials = JSON.parse(credentialsCookie.value);
if (!credentials.email || !credentials.password || !credentials.host || !credentials.port) {
return null;
}
return credentials;
} catch (error) {
return null;
}
}
export async function POST(request: Request) { export async function POST(request: Request) {
try { try {
@ -16,44 +43,108 @@ export async function POST(request: Request) {
const url = new URL(request.url); const url = new URL(request.url);
const folder = url.searchParams.get('folder') || 'INBOX'; const folder = url.searchParams.get('folder') || 'INBOX';
// Get the IMAP client using the same method as the mail endpoint // Get stored credentials
const imap = await getImapClient(); const credentials = getStoredCredentials();
if (!imap) { if (!credentials) {
return NextResponse.json( return NextResponse.json(
{ error: 'Failed to connect to mail server' }, { error: 'No stored credentials found' },
{ status: 500 } { status: 401 }
); );
} }
// Convert string ID to number return new Promise((resolve) => {
const numericId = parseInt(emailId, 10); const imap = new Imap({
user: credentials.email,
// Get mailbox lock for the current folder password: credentials.password,
const lock = await imap.getMailboxLock(folder); host: credentials.host,
port: credentials.port,
try { tls: true,
// Fetch message to get its UID tlsOptions: { rejectUnauthorized: false },
const messages = await imap.fetch({ authTimeout: 30000,
seq: numericId.toString(), connTimeout: 30000
uid: true,
envelope: true
}); });
// Process the message const timeout = setTimeout(() => {
for await (const message of messages) { console.error('IMAP connection timeout');
if (!message.uid) continue; imap.end();
resolve(NextResponse.json({ error: 'Connection timeout' }));
}, 30000);
if (isRead) { imap.once('error', (err: Error) => {
await imap.messageFlagsAdd(message.uid, ['\\Seen'], { uid: true }); console.error('IMAP error:', err);
} else { clearTimeout(timeout);
await imap.messageFlagsRemove(message.uid, ['\\Seen'], { uid: true }); resolve(NextResponse.json({ error: 'IMAP connection error' }));
} });
}
return NextResponse.json({ success: true }); imap.once('ready', () => {
} finally { imap.openBox(folder, false, (err, box) => {
lock.release(); if (err) {
} console.error(`Error opening box ${folder}:`, err);
clearTimeout(timeout);
imap.end();
resolve(NextResponse.json({ error: `Failed to open folder ${folder}` }));
return;
}
// Convert string ID to number
const numericId = parseInt(emailId, 10);
const fetch = imap.fetch(numericId.toString(), {
bodies: '',
struct: true
});
fetch.on('message', (msg) => {
msg.once('attributes', (attrs) => {
const uid = attrs.uid;
if (!uid) {
clearTimeout(timeout);
imap.end();
resolve(NextResponse.json({ error: 'No UID found for email' }));
return;
}
if (isRead) {
imap.addFlags(uid, ['\\Seen'], (err) => {
if (err) {
console.error('Error marking as read:', err);
clearTimeout(timeout);
imap.end();
resolve(NextResponse.json({ error: 'Failed to mark as read' }));
return;
}
clearTimeout(timeout);
imap.end();
resolve(NextResponse.json({ success: true }));
});
} else {
imap.removeFlags(uid, ['\\Seen'], (err) => {
if (err) {
console.error('Error marking as unread:', err);
clearTimeout(timeout);
imap.end();
resolve(NextResponse.json({ error: 'Failed to mark as unread' }));
return;
}
clearTimeout(timeout);
imap.end();
resolve(NextResponse.json({ success: true }));
});
}
});
});
fetch.on('error', (err) => {
console.error('Error fetching email:', err);
clearTimeout(timeout);
imap.end();
resolve(NextResponse.json({ error: 'Failed to fetch email' }));
});
});
});
imap.connect();
});
} catch (error) { } catch (error) {
console.error('Error marking email as read:', error); console.error('Error marking email as read:', error);
return NextResponse.json( return NextResponse.json(