mail page imap connection mime 5 bis rest 16 login page
This commit is contained in:
parent
926bd48b5e
commit
5b2eb5286a
2
.env
2
.env
@ -67,6 +67,6 @@ DB_NAME=rivacube
|
||||
|
||||
# IMAP Configuration
|
||||
IMAP_USER=alma@governance-labs.org
|
||||
IMAP_PASSWORD=your_imap_password_here
|
||||
IMAP_PASSWORD=8s-hN8u37-IP#-y
|
||||
IMAP_HOST=mail.infomaniak.com
|
||||
IMAP_PORT=993
|
||||
|
||||
@ -11,42 +11,58 @@ console.log('Environment Variables:', {
|
||||
NODE_ENV: process.env.NODE_ENV
|
||||
});
|
||||
|
||||
// Helper function to get stored credentials
|
||||
function getStoredCredentials() {
|
||||
if (typeof window === 'undefined') {
|
||||
// Server-side: use environment variables
|
||||
return {
|
||||
user: process.env.IMAP_USER,
|
||||
password: process.env.IMAP_PASSWORD,
|
||||
host: process.env.IMAP_HOST,
|
||||
port: process.env.IMAP_PORT
|
||||
};
|
||||
}
|
||||
|
||||
// Client-side: use localStorage
|
||||
const stored = localStorage.getItem('imapCredentials');
|
||||
return stored ? JSON.parse(stored) : null;
|
||||
}
|
||||
|
||||
// IMAP configuration
|
||||
const imapConfig: Imap.Config = {
|
||||
user: process.env.IMAP_USER || 'alma@governance-labs.org',
|
||||
password: process.env.IMAP_PASSWORD || '',
|
||||
host: process.env.IMAP_HOST || 'mail.infomaniak.com',
|
||||
port: parseInt(process.env.IMAP_PORT || '993', 10),
|
||||
tls: true,
|
||||
tlsOptions: {
|
||||
rejectUnauthorized: false,
|
||||
servername: process.env.IMAP_HOST || 'mail.infomaniak.com'
|
||||
},
|
||||
authTimeout: 10000,
|
||||
connTimeout: 10000,
|
||||
debug: console.log // Enable IMAP debug logging
|
||||
const getImapConfig = () => {
|
||||
const credentials = getStoredCredentials();
|
||||
|
||||
if (!credentials?.user || !credentials?.password) {
|
||||
throw new Error('Email credentials not found. Please log in first.');
|
||||
}
|
||||
|
||||
return {
|
||||
user: credentials.user,
|
||||
password: credentials.password,
|
||||
host: credentials.host || 'mail.infomaniak.com',
|
||||
port: parseInt(credentials.port || '993', 10),
|
||||
tls: true,
|
||||
tlsOptions: {
|
||||
rejectUnauthorized: false,
|
||||
servername: credentials.host || 'mail.infomaniak.com'
|
||||
},
|
||||
authTimeout: 10000,
|
||||
connTimeout: 10000,
|
||||
debug: console.log
|
||||
};
|
||||
};
|
||||
|
||||
// Debug logging for IMAP configuration
|
||||
console.log('IMAP Configuration:', {
|
||||
user: imapConfig.user,
|
||||
host: imapConfig.host,
|
||||
port: imapConfig.port,
|
||||
tls: imapConfig.tls,
|
||||
hasPassword: !!imapConfig.password,
|
||||
authTimeout: imapConfig.authTimeout,
|
||||
connTimeout: imapConfig.connTimeout
|
||||
user: getImapConfig().user,
|
||||
host: getImapConfig().host,
|
||||
port: getImapConfig().port,
|
||||
tls: getImapConfig().tls,
|
||||
hasPassword: !!getImapConfig().password,
|
||||
authTimeout: getImapConfig().authTimeout,
|
||||
connTimeout: getImapConfig().connTimeout
|
||||
});
|
||||
|
||||
// Validate IMAP configuration
|
||||
if (!imapConfig.user || !imapConfig.password) {
|
||||
console.error('IMAP configuration error:', {
|
||||
user: imapConfig.user,
|
||||
hasPassword: !!imapConfig.password
|
||||
});
|
||||
throw new Error('IMAP credentials are not properly configured. Please check your .env file.');
|
||||
}
|
||||
|
||||
interface ImapMessage {
|
||||
header: {
|
||||
from?: string[];
|
||||
@ -68,7 +84,7 @@ interface ImapError extends Error {
|
||||
}
|
||||
|
||||
// Helper function to create a promise-based IMAP connection
|
||||
function createImapConnection() {
|
||||
function createImapConnection(imapConfig: Imap.Config) {
|
||||
return new Promise((resolve, reject) => {
|
||||
console.log('Creating new IMAP connection with config:', {
|
||||
user: imapConfig.user,
|
||||
@ -179,17 +195,17 @@ export async function GET(request: Request) {
|
||||
try {
|
||||
console.log('Starting email fetch process...');
|
||||
|
||||
// Validate IMAP configuration
|
||||
if (!imapConfig.user || !imapConfig.password) {
|
||||
console.error('IMAP configuration error:', {
|
||||
user: imapConfig.user,
|
||||
hasPassword: !!imapConfig.password
|
||||
});
|
||||
throw new Error('IMAP credentials are not properly configured. Please check your .env file.');
|
||||
}
|
||||
const imapConfig = getImapConfig();
|
||||
console.log('IMAP Configuration:', {
|
||||
user: imapConfig.user,
|
||||
host: imapConfig.host,
|
||||
port: imapConfig.port,
|
||||
tls: imapConfig.tls,
|
||||
hasPassword: !!imapConfig.password
|
||||
});
|
||||
|
||||
console.log('Creating IMAP connection...');
|
||||
const imap = await createImapConnection() as Imap;
|
||||
const imap = await createImapConnection(imapConfig) as Imap;
|
||||
|
||||
console.log('Fetching messages...');
|
||||
const messages = await fetchMessages(imap, 'INBOX');
|
||||
@ -226,7 +242,7 @@ export async function GET(request: Request) {
|
||||
// Add endpoint to get mailboxes
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const imap = await createImapConnection() as Imap;
|
||||
const imap = await createImapConnection(getImapConfig()) as Imap;
|
||||
|
||||
const mailboxes = await new Promise((resolve, reject) => {
|
||||
imap.getBoxes((err, boxes) => {
|
||||
|
||||
50
app/api/mail/test-connection/route.ts
Normal file
50
app/api/mail/test-connection/route.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import Imap from 'imap';
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const { email, password, host, port } = await request.json();
|
||||
|
||||
// IMAP configuration
|
||||
const imapConfig: Imap.Config = {
|
||||
user: email,
|
||||
password: password,
|
||||
host: host,
|
||||
port: parseInt(port, 10),
|
||||
tls: true,
|
||||
tlsOptions: {
|
||||
rejectUnauthorized: false,
|
||||
servername: host
|
||||
},
|
||||
authTimeout: 10000,
|
||||
connTimeout: 10000
|
||||
};
|
||||
|
||||
// Create a promise-based IMAP connection
|
||||
const imap = new Imap(imapConfig);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
imap.once('ready', () => {
|
||||
imap.end();
|
||||
resolve(NextResponse.json({ success: true }));
|
||||
});
|
||||
|
||||
imap.once('error', (err: Error) => {
|
||||
console.error('IMAP connection error:', err);
|
||||
reject(NextResponse.json({
|
||||
error: 'Failed to connect to email server',
|
||||
details: err.message
|
||||
}, { status: 401 }));
|
||||
});
|
||||
|
||||
imap.connect();
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error in test connection:', error);
|
||||
return NextResponse.json({
|
||||
error: 'Failed to test connection',
|
||||
details: error instanceof Error ? error.message : 'Unknown error'
|
||||
}, { status: 500 });
|
||||
}
|
||||
}
|
||||
112
app/mail/login/page.tsx
Normal file
112
app/mail/login/page.tsx
Normal file
@ -0,0 +1,112 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
export default function EmailLoginPage() {
|
||||
const router = useRouter();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [credentials, setCredentials] = useState({
|
||||
email: '',
|
||||
password: '',
|
||||
host: 'mail.infomaniak.com',
|
||||
port: '993'
|
||||
});
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
// Store credentials in localStorage
|
||||
localStorage.setItem('imapCredentials', JSON.stringify(credentials));
|
||||
|
||||
// Test the connection
|
||||
const response = await fetch('/api/mail/test-connection', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(credentials),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to connect to email server');
|
||||
}
|
||||
|
||||
toast.success('Successfully connected to email server');
|
||||
router.push('/mail');
|
||||
} catch (error) {
|
||||
console.error('Login error:', error);
|
||||
toast.error('Failed to connect to email server. Please check your credentials.');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center bg-gray-50">
|
||||
<Card className="w-full max-w-md">
|
||||
<CardHeader>
|
||||
<CardTitle>Email Login</CardTitle>
|
||||
<CardDescription>
|
||||
Enter your email credentials to access your mailbox
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="email">Email Address</Label>
|
||||
<Input
|
||||
id="email"
|
||||
type="email"
|
||||
placeholder="your@email.com"
|
||||
value={credentials.email}
|
||||
onChange={(e) => setCredentials({ ...credentials, email: e.target.value })}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="password">Password</Label>
|
||||
<Input
|
||||
id="password"
|
||||
type="password"
|
||||
value={credentials.password}
|
||||
onChange={(e) => setCredentials({ ...credentials, password: e.target.value })}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="host">IMAP Host</Label>
|
||||
<Input
|
||||
id="host"
|
||||
type="text"
|
||||
value={credentials.host}
|
||||
onChange={(e) => setCredentials({ ...credentials, host: e.target.value })}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="port">IMAP Port</Label>
|
||||
<Input
|
||||
id="port"
|
||||
type="text"
|
||||
value={credentials.port}
|
||||
onChange={(e) => setCredentials({ ...credentials, port: e.target.value })}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<Button type="submit" className="w-full" disabled={loading}>
|
||||
{loading ? 'Connecting...' : 'Connect'}
|
||||
</Button>
|
||||
</form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -19,6 +19,7 @@ import {
|
||||
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { MoreVertical, Settings, Plus as PlusIcon, Trash2, Edit, Mail, Inbox, Send, Star, Trash, Plus, ChevronLeft, ChevronRight, Search, ChevronDown, Folder, ChevronUp, Reply, Forward, ReplyAll, MoreHorizontal, FolderOpen, X, Paperclip, MessageSquare } from 'lucide-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
interface Account {
|
||||
id: number;
|
||||
@ -386,6 +387,30 @@ function decodeMimeContent(content: string): string {
|
||||
}
|
||||
|
||||
export default function MailPage() {
|
||||
const router = useRouter();
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
// Check for stored credentials
|
||||
const storedCredentials = localStorage.getItem('imapCredentials');
|
||||
if (!storedCredentials) {
|
||||
router.push('/mail/login');
|
||||
} else {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [router]);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center">
|
||||
<div className="text-center">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-gray-900 mx-auto"></div>
|
||||
<p className="mt-4 text-gray-600">Loading...</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Single IMAP account for now
|
||||
const [accounts, setAccounts] = useState<Account[]>([
|
||||
{ id: 1, name: 'Mail', email: 'alma@governance-labs.org', color: 'bg-blue-500' },
|
||||
@ -411,7 +436,6 @@ export default function MailPage() {
|
||||
const [showCc, setShowCc] = useState(false);
|
||||
const [showBcc, setShowBcc] = useState(false);
|
||||
const [emails, setEmails] = useState<Email[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [composeSubject, setComposeSubject] = useState('');
|
||||
const [composeRecipient, setComposeRecipient] = useState('');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user