155 lines
4.5 KiB
TypeScript
155 lines
4.5 KiB
TypeScript
import { NextResponse } from 'next/server';
|
|
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) {
|
|
try {
|
|
const { emailId, isRead } = await request.json();
|
|
|
|
if (!emailId || typeof isRead !== 'boolean') {
|
|
return NextResponse.json(
|
|
{ error: 'Invalid request parameters' },
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
// Get the current folder from the request URL
|
|
const url = new URL(request.url);
|
|
const folder = url.searchParams.get('folder') || 'INBOX';
|
|
|
|
// Get stored credentials
|
|
const credentials = getStoredCredentials();
|
|
if (!credentials) {
|
|
return NextResponse.json(
|
|
{ error: 'No stored credentials found' },
|
|
{ status: 401 }
|
|
);
|
|
}
|
|
|
|
return new Promise((resolve) => {
|
|
const imap = new Imap({
|
|
user: credentials.email,
|
|
password: credentials.password,
|
|
host: credentials.host,
|
|
port: credentials.port,
|
|
tls: true,
|
|
tlsOptions: { rejectUnauthorized: false },
|
|
authTimeout: 30000,
|
|
connTimeout: 30000
|
|
});
|
|
|
|
const timeout = setTimeout(() => {
|
|
console.error('IMAP connection timeout');
|
|
imap.end();
|
|
resolve(NextResponse.json({ error: 'Connection timeout' }));
|
|
}, 30000);
|
|
|
|
imap.once('error', (err: Error) => {
|
|
console.error('IMAP error:', err);
|
|
clearTimeout(timeout);
|
|
resolve(NextResponse.json({ error: 'IMAP connection error' }));
|
|
});
|
|
|
|
imap.once('ready', () => {
|
|
imap.openBox(folder, false, (err, box) => {
|
|
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) {
|
|
console.error('Error marking email as read:', error);
|
|
return NextResponse.json(
|
|
{ error: 'Failed to mark email as read' },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|