github-actions[bot]
Update from GitHub Actions
7fc5208
raw
history blame
7.31 kB
import PostalMime from 'postal-mime';
export async function get_access_token(tokenInfo: any, client_id: string, clientSecret: string) {
// 检查token是否过期(提前5分钟刷新)
const now = Date.now();
const expiryTime = tokenInfo.timestamp + (tokenInfo.expires_in * 1000);
const shouldRefresh = now >= (expiryTime - 300000); // 5分钟 = 300000毫秒
if (!shouldRefresh) {
return tokenInfo.access_token;
}
const response = await fetch('https://login.microsoftonline.com/common/oauth2/v2.0/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
'client_id': client_id,
'client_secret': clientSecret,
'grant_type': 'refresh_token',
'refresh_token': tokenInfo.refresh_token
})
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`HTTP error! status: ${response.status}, response: ${errorText}`);
}
const data = await response.json() as any;
return data.access_token;
}
//https://learn.microsoft.com/zh-cn/graph/api/resources/mail-api-overview?view=graph-rest-1.0
/**
* 获取邮件列表
*/
interface ParsedEmail {
id: string;
subject: string;
from: string;
to: string[];
date: {
created: string;
received: string;
sent: string;
modified: string;
};
text: string;
html: string;
importance: string;
isRead: boolean;
isDraft: boolean;
hasAttachments: boolean;
webLink: string;
preview: string;
categories: string[];
internetMessageId: string;
metadata: {
platform?: string;
browser?: string;
ip?: string;
location?: string;
};
}
async function parseEmail(email: any): Promise<ParsedEmail> {
const parser = new PostalMime();
let content = '';
try {
if (email.body.content) {
content = email.body.content;
} else {
const response = await fetch(email.body.contentUrl);
content = await response.text();
}
const parsed = await parser.parse(content);
// 从HTML内容中提取元数据
const htmlContent = email.body.content || '';
const platformMatch = htmlContent.match(/Platform:\s*([^<\r\n]+)/);
const browserMatch = htmlContent.match(/Browser:\s*([^<\r\n]+)/);
const ipMatch = htmlContent.match(/IP address:\s*([^<\r\n]+)/);
const locationMatch = htmlContent.match(/Country\/region:\s*([^<\r\n]+)/);
return {
id: email.id,
subject: email.subject,
from: email.from.emailAddress.address,
to: email.toRecipients.map((r: any) => r.emailAddress.address),
date: {
created: email.createdDateTime,
received: email.receivedDateTime,
sent: email.sentDateTime,
modified: email.lastModifiedDateTime
},
text: parsed.text || email.bodyPreview || '',
html: parsed.html || email.body.content || '',
importance: email.importance,
isRead: email.isRead,
isDraft: email.isDraft,
hasAttachments: email.hasAttachments,
webLink: email.webLink,
preview: email.bodyPreview,
categories: email.categories,
internetMessageId: email.internetMessageId,
metadata: {
platform: platformMatch?.[1]?.trim(),
browser: browserMatch?.[1]?.trim(),
ip: ipMatch?.[1]?.trim(),
location: locationMatch?.[1]?.trim(),
}
};
} catch (error) {
console.error('解析邮件失败:', error);
return {
id: email.id,
subject: email.subject,
from: email.from.emailAddress.address,
to: email.toRecipients.map((r: any) => r.emailAddress.address),
date: {
created: email.createdDateTime,
received: email.receivedDateTime,
sent: email.sentDateTime,
modified: email.lastModifiedDateTime
},
text: email.bodyPreview || '',
html: email.body.content || '',
importance: email.importance,
isRead: email.isRead,
isDraft: email.isDraft,
hasAttachments: email.hasAttachments,
webLink: email.webLink,
preview: email.bodyPreview,
categories: email.categories,
internetMessageId: email.internetMessageId,
metadata: {}
};
}
}
export async function getEmails(accessToken: string, limit = 50): Promise<ParsedEmail[]> {
const endpoint = 'https://graph.microsoft.com/v1.0/me/messages';
console.log(accessToken)
const response = await fetch(`${endpoint}?$top=${limit}`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
}
});
const data = await response.json() as any;
if (!response.ok) {
throw new Error(`获取邮件失败: ${data.error?.message}`);
}
const emails = data.value;
console.log(emails)
const parsedEmails = await Promise.all(emails.map(parseEmail));
return parsedEmails;
}
/**
* 删除单个邮件
*/
export async function deleteEmail(accessToken: string, emailId: string): Promise<void> {
const endpoint = `https://graph.microsoft.com/v1.0/me/messages/${emailId}`;
const response = await fetch(endpoint, {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${accessToken}`
}
});
if (!response.ok) {
const errorData = await response.json() as any;
throw new Error(`删除邮件失败: ${errorData.error?.message}`);
}
}
/**
* 清空邮箱 (批量删除邮件)
*/
export async function emptyMailbox(accessToken: string, batchSize = 50): Promise<void> {
let hasMoreEmails = true;
let totalDeleted = 0;
while (hasMoreEmails) {
// 获取一批邮件
const emails = await getEmails(accessToken, batchSize);
if (emails.length === 0) {
hasMoreEmails = false;
break;
}
// 删除该批次的每封邮件
const deletePromises = emails.map(email => deleteEmail(accessToken, email.id));
await Promise.all(deletePromises);
totalDeleted += emails.length;
console.log(`已删除 ${emails.length} 封邮件,累计: ${totalDeleted}`);
}
console.log('邮箱已清空');
}
/**
* 发送邮件
*/
export async function sendEmail(
accessToken: string,
to: string[],
subject: string,
body: string,
isHtml = false
): Promise<void> {
const endpoint = 'https://graph.microsoft.com/v1.0/me/sendMail';
const emailData = {
message: {
subject,
body: {
contentType: isHtml ? 'HTML' : 'Text',
content: body
},
toRecipients: to.map(recipient => ({
emailAddress: {
address: recipient
}
}))
}
};
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(emailData)
});
if (!response.ok) {
const errorData = await response.json() as any;
throw new Error(`发送邮件失败: ${errorData.error?.message}`);
}
}