courrier msft oauth
This commit is contained in:
parent
b97c2310b8
commit
49dd79e3ba
@ -19,7 +19,10 @@ import {
|
||||
} from '@/lib/redis';
|
||||
import { EmailCredentials, EmailMessage, EmailAddress, EmailAttachment } from '@/lib/types';
|
||||
import { ensureFreshToken } from './token-refresh';
|
||||
import { createXOAuth2Token } from './microsoft-oauth';
|
||||
import { createXOAuth2Token, refreshAccessToken as refreshMicrosoftAccessToken } from './microsoft-oauth';
|
||||
import { MailCredentials } from '@prisma/client';
|
||||
import Redis from 'ioredis';
|
||||
import { getRedisClient } from '../redis';
|
||||
|
||||
// Define EmailCredentials interface with OAuth properties
|
||||
interface EmailCredentialsExtended extends EmailCredentials {
|
||||
@ -346,36 +349,57 @@ async function createImapConnection(credentials: EmailCredentials, connectionKey
|
||||
// Cast to extended type
|
||||
const extendedCreds = credentials as EmailCredentialsExtended;
|
||||
|
||||
// Configure auth
|
||||
let auth: any = {
|
||||
user: extendedCreds.email
|
||||
};
|
||||
let authParams: any;
|
||||
|
||||
// Check if we should use OAuth
|
||||
if (extendedCreds.useOAuth && extendedCreds.accessToken) {
|
||||
// For OAuth, create the proper XOAUTH2 token format
|
||||
const xoauth2 = createXOAuth2Token(extendedCreds.email, extendedCreds.accessToken);
|
||||
auth.xoauth2 = xoauth2;
|
||||
// Configure for XOAUTH2
|
||||
console.log(`Using XOAUTH2 authentication for ${connectionKey}`);
|
||||
|
||||
// Generate the XOAUTH2 token
|
||||
const xoauth2Token = createXOAuth2Token(extendedCreds.email, extendedCreds.accessToken);
|
||||
|
||||
// Set auth parameters for ImapFlow
|
||||
authParams = {
|
||||
user: extendedCreds.email,
|
||||
// IMPORTANT: For ImapFlow, we need to provide the accessToken directly
|
||||
// The library will handle converting it to XOAUTH2 format internally
|
||||
accessToken: extendedCreds.accessToken
|
||||
};
|
||||
|
||||
console.log(`XOAUTH2 auth configured for ${connectionKey}`);
|
||||
} else {
|
||||
auth.pass = extendedCreds.password;
|
||||
// Use regular password authentication
|
||||
console.log(`Using password authentication for ${connectionKey}`);
|
||||
authParams = {
|
||||
user: extendedCreds.email,
|
||||
pass: extendedCreds.password
|
||||
};
|
||||
}
|
||||
|
||||
console.log(`Creating ImapFlow client for ${connectionKey} with authentication type: ${extendedCreds.useOAuth ? 'OAuth' : 'Password'}`);
|
||||
|
||||
const client = new ImapFlow({
|
||||
host: extendedCreds.host,
|
||||
port: extendedCreds.port,
|
||||
secure: extendedCreds.secure ?? true,
|
||||
auth,
|
||||
auth: authParams,
|
||||
logger: false,
|
||||
emitLogs: false,
|
||||
tls: {
|
||||
rejectUnauthorized: false
|
||||
},
|
||||
// Connection timeout settings
|
||||
disableAutoIdle: false // Keep idle to auto-refresh connection
|
||||
disableAutoIdle: false
|
||||
});
|
||||
|
||||
await client.connect();
|
||||
try {
|
||||
console.log(`Connecting to IMAP server: ${extendedCreds.host}:${extendedCreds.port}`);
|
||||
await client.connect();
|
||||
console.log(`Successfully connected to IMAP server for ${connectionKey}`);
|
||||
} catch (error) {
|
||||
console.error(`Failed to connect to IMAP server for ${connectionKey}:`, error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Add error handler
|
||||
client.on('error', (err) => {
|
||||
@ -979,9 +1003,21 @@ export async function toggleEmailFlag(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an email
|
||||
*/
|
||||
// Define EmailContent interface
|
||||
interface EmailContent {
|
||||
to: string;
|
||||
cc?: string;
|
||||
bcc?: string;
|
||||
subject: string;
|
||||
plainText: string;
|
||||
htmlContent: string;
|
||||
attachments?: Array<{
|
||||
filename: string;
|
||||
content: string;
|
||||
contentType: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export async function sendEmail(
|
||||
userId: string,
|
||||
emailData: {
|
||||
@ -1005,33 +1041,32 @@ export async function sendEmail(
|
||||
error: 'No email credentials found'
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// Cast to extended type
|
||||
const extendedCreds = credentials as EmailCredentialsExtended;
|
||||
|
||||
// Configure SMTP auth based on OAuth or password
|
||||
let auth: any = {
|
||||
user: extendedCreds.email
|
||||
};
|
||||
const smtpAuth = extendedCreds.useOAuth && extendedCreds.accessToken
|
||||
? {
|
||||
type: 'OAuth2',
|
||||
user: extendedCreds.email,
|
||||
accessToken: extendedCreds.accessToken
|
||||
}
|
||||
: {
|
||||
user: extendedCreds.email,
|
||||
pass: extendedCreds.password
|
||||
};
|
||||
|
||||
if (extendedCreds.useOAuth && extendedCreds.accessToken) {
|
||||
// For OAuth, use the XOAuth2 format
|
||||
auth.type = 'OAuth2';
|
||||
auth.accessToken = extendedCreds.accessToken;
|
||||
} else {
|
||||
auth.pass = extendedCreds.password;
|
||||
}
|
||||
|
||||
// Create SMTP transporter with user's SMTP settings if available
|
||||
// Create SMTP transporter with user's SMTP settings
|
||||
const transporter = nodemailer.createTransport({
|
||||
host: extendedCreds.smtp_host || 'smtp.infomaniak.com',
|
||||
port: extendedCreds.smtp_port || 587,
|
||||
secure: extendedCreds.smtp_secure || false,
|
||||
auth,
|
||||
auth: smtpAuth,
|
||||
tls: {
|
||||
rejectUnauthorized: false
|
||||
}
|
||||
} as any);
|
||||
} as nodemailer.TransportOptions);
|
||||
|
||||
try {
|
||||
const info = await transporter.sendMail({
|
||||
@ -1054,6 +1089,7 @@ export async function sendEmail(
|
||||
messageId: info.messageId
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Failed to send email:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error'
|
||||
@ -1106,25 +1142,32 @@ export async function testEmailConnection(credentials: EmailCredentials): Promis
|
||||
console.log(`Testing IMAP connection to ${extendedCreds.host}:${extendedCreds.port} for ${extendedCreds.email}`);
|
||||
|
||||
// Configure auth based on whether we're using OAuth or password
|
||||
let auth: any = {
|
||||
user: extendedCreds.email
|
||||
};
|
||||
let authParams: any;
|
||||
|
||||
if (extendedCreds.useOAuth && extendedCreds.accessToken) {
|
||||
// For OAuth, create the proper XOAUTH2 token format
|
||||
const xoauth2 = createXOAuth2Token(extendedCreds.email, extendedCreds.accessToken);
|
||||
auth.xoauth2 = xoauth2;
|
||||
console.log('Using XOAUTH2 authentication mechanism');
|
||||
|
||||
// For OAuth, pass the accessToken directly to ImapFlow
|
||||
authParams = {
|
||||
user: extendedCreds.email,
|
||||
accessToken: extendedCreds.accessToken
|
||||
};
|
||||
|
||||
// Log the token length to verify it exists
|
||||
console.log(`Access token available (length: ${extendedCreds.accessToken.length})`);
|
||||
} else {
|
||||
auth.pass = extendedCreds.password;
|
||||
console.log('Using password authentication mechanism');
|
||||
authParams = {
|
||||
user: extendedCreds.email,
|
||||
pass: extendedCreds.password
|
||||
};
|
||||
}
|
||||
|
||||
const client = new ImapFlow({
|
||||
host: extendedCreds.host,
|
||||
port: extendedCreds.port,
|
||||
secure: extendedCreds.secure ?? true,
|
||||
auth,
|
||||
auth: authParams,
|
||||
logger: false,
|
||||
tls: {
|
||||
rejectUnauthorized: false
|
||||
@ -1148,8 +1191,9 @@ export async function testEmailConnection(credentials: EmailCredentials): Promis
|
||||
console.log(`Testing SMTP connection to ${extendedCreds.smtp_host}:${extendedCreds.smtp_port}`);
|
||||
|
||||
// Configure SMTP auth based on OAuth or password
|
||||
const smtpAuth = extendedCreds.useOAuth
|
||||
const smtpAuth = extendedCreds.useOAuth && extendedCreds.accessToken
|
||||
? {
|
||||
type: 'OAuth2',
|
||||
user: extendedCreds.email,
|
||||
accessToken: extendedCreds.accessToken
|
||||
}
|
||||
@ -1166,7 +1210,7 @@ export async function testEmailConnection(credentials: EmailCredentials): Promis
|
||||
tls: {
|
||||
rejectUnauthorized: false
|
||||
}
|
||||
});
|
||||
} as nodemailer.TransportOptions);
|
||||
|
||||
await transporter.verify();
|
||||
console.log(`SMTP connection successful for ${extendedCreds.email}`);
|
||||
|
||||
@ -150,6 +150,11 @@ export async function refreshAccessToken(refreshToken: string): Promise<{
|
||||
* Create special XOAUTH2 string for IMAP authentication
|
||||
*/
|
||||
export function createXOAuth2Token(email: string, accessToken: string): string {
|
||||
// This creates the XOAUTH2 token in the required format for ImapFlow
|
||||
// Format: user=<email>\x01auth=Bearer <token>\x01\x01
|
||||
const auth = `user=${email}\x01auth=Bearer ${accessToken}\x01\x01`;
|
||||
return Buffer.from(auth).toString('base64');
|
||||
const base64Auth = Buffer.from(auth).toString('base64');
|
||||
|
||||
console.log('Generated XOAUTH2 token (length):', base64Auth.length);
|
||||
return base64Auth;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user