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 Configuration
|
||||||
IMAP_USER=alma@governance-labs.org
|
IMAP_USER=alma@governance-labs.org
|
||||||
IMAP_PASSWORD=your_imap_password_here
|
IMAP_PASSWORD=8s-hN8u37-IP#-y
|
||||||
IMAP_HOST=mail.infomaniak.com
|
IMAP_HOST=mail.infomaniak.com
|
||||||
IMAP_PORT=993
|
IMAP_PORT=993
|
||||||
|
|||||||
@ -11,42 +11,58 @@ console.log('Environment Variables:', {
|
|||||||
NODE_ENV: process.env.NODE_ENV
|
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
|
// IMAP configuration
|
||||||
const imapConfig: Imap.Config = {
|
const getImapConfig = () => {
|
||||||
user: process.env.IMAP_USER || 'alma@governance-labs.org',
|
const credentials = getStoredCredentials();
|
||||||
password: process.env.IMAP_PASSWORD || '',
|
|
||||||
host: process.env.IMAP_HOST || 'mail.infomaniak.com',
|
if (!credentials?.user || !credentials?.password) {
|
||||||
port: parseInt(process.env.IMAP_PORT || '993', 10),
|
throw new Error('Email credentials not found. Please log in first.');
|
||||||
tls: true,
|
}
|
||||||
tlsOptions: {
|
|
||||||
rejectUnauthorized: false,
|
return {
|
||||||
servername: process.env.IMAP_HOST || 'mail.infomaniak.com'
|
user: credentials.user,
|
||||||
},
|
password: credentials.password,
|
||||||
authTimeout: 10000,
|
host: credentials.host || 'mail.infomaniak.com',
|
||||||
connTimeout: 10000,
|
port: parseInt(credentials.port || '993', 10),
|
||||||
debug: console.log // Enable IMAP debug logging
|
tls: true,
|
||||||
|
tlsOptions: {
|
||||||
|
rejectUnauthorized: false,
|
||||||
|
servername: credentials.host || 'mail.infomaniak.com'
|
||||||
|
},
|
||||||
|
authTimeout: 10000,
|
||||||
|
connTimeout: 10000,
|
||||||
|
debug: console.log
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Debug logging for IMAP configuration
|
// Debug logging for IMAP configuration
|
||||||
console.log('IMAP Configuration:', {
|
console.log('IMAP Configuration:', {
|
||||||
user: imapConfig.user,
|
user: getImapConfig().user,
|
||||||
host: imapConfig.host,
|
host: getImapConfig().host,
|
||||||
port: imapConfig.port,
|
port: getImapConfig().port,
|
||||||
tls: imapConfig.tls,
|
tls: getImapConfig().tls,
|
||||||
hasPassword: !!imapConfig.password,
|
hasPassword: !!getImapConfig().password,
|
||||||
authTimeout: imapConfig.authTimeout,
|
authTimeout: getImapConfig().authTimeout,
|
||||||
connTimeout: imapConfig.connTimeout
|
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 {
|
interface ImapMessage {
|
||||||
header: {
|
header: {
|
||||||
from?: string[];
|
from?: string[];
|
||||||
@ -68,7 +84,7 @@ interface ImapError extends Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to create a promise-based IMAP connection
|
// Helper function to create a promise-based IMAP connection
|
||||||
function createImapConnection() {
|
function createImapConnection(imapConfig: Imap.Config) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
console.log('Creating new IMAP connection with config:', {
|
console.log('Creating new IMAP connection with config:', {
|
||||||
user: imapConfig.user,
|
user: imapConfig.user,
|
||||||
@ -179,17 +195,17 @@ export async function GET(request: Request) {
|
|||||||
try {
|
try {
|
||||||
console.log('Starting email fetch process...');
|
console.log('Starting email fetch process...');
|
||||||
|
|
||||||
// Validate IMAP configuration
|
const imapConfig = getImapConfig();
|
||||||
if (!imapConfig.user || !imapConfig.password) {
|
console.log('IMAP Configuration:', {
|
||||||
console.error('IMAP configuration error:', {
|
user: imapConfig.user,
|
||||||
user: imapConfig.user,
|
host: imapConfig.host,
|
||||||
hasPassword: !!imapConfig.password
|
port: imapConfig.port,
|
||||||
});
|
tls: imapConfig.tls,
|
||||||
throw new Error('IMAP credentials are not properly configured. Please check your .env file.');
|
hasPassword: !!imapConfig.password
|
||||||
}
|
});
|
||||||
|
|
||||||
console.log('Creating IMAP connection...');
|
console.log('Creating IMAP connection...');
|
||||||
const imap = await createImapConnection() as Imap;
|
const imap = await createImapConnection(imapConfig) as Imap;
|
||||||
|
|
||||||
console.log('Fetching messages...');
|
console.log('Fetching messages...');
|
||||||
const messages = await fetchMessages(imap, 'INBOX');
|
const messages = await fetchMessages(imap, 'INBOX');
|
||||||
@ -226,7 +242,7 @@ export async function GET(request: Request) {
|
|||||||
// Add endpoint to get mailboxes
|
// Add endpoint to get mailboxes
|
||||||
export async function POST(request: Request) {
|
export async function POST(request: Request) {
|
||||||
try {
|
try {
|
||||||
const imap = await createImapConnection() as Imap;
|
const imap = await createImapConnection(getImapConfig()) as Imap;
|
||||||
|
|
||||||
const mailboxes = await new Promise((resolve, reject) => {
|
const mailboxes = await new Promise((resolve, reject) => {
|
||||||
imap.getBoxes((err, boxes) => {
|
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 { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
||||||
import { Label } from "@/components/ui/label";
|
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 { 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 {
|
interface Account {
|
||||||
id: number;
|
id: number;
|
||||||
@ -386,6 +387,30 @@ function decodeMimeContent(content: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function MailPage() {
|
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
|
// Single IMAP account for now
|
||||||
const [accounts, setAccounts] = useState<Account[]>([
|
const [accounts, setAccounts] = useState<Account[]>([
|
||||||
{ id: 1, name: 'Mail', email: 'alma@governance-labs.org', color: 'bg-blue-500' },
|
{ 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 [showCc, setShowCc] = useState(false);
|
||||||
const [showBcc, setShowBcc] = useState(false);
|
const [showBcc, setShowBcc] = useState(false);
|
||||||
const [emails, setEmails] = useState<Email[]>([]);
|
const [emails, setEmails] = useState<Email[]>([]);
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [composeSubject, setComposeSubject] = useState('');
|
const [composeSubject, setComposeSubject] = useState('');
|
||||||
const [composeRecipient, setComposeRecipient] = useState('');
|
const [composeRecipient, setComposeRecipient] = useState('');
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user