diff --git a/worker/src/telegram_api/telegram.ts b/worker/src/telegram_api/telegram.ts index 3fe1f739..086a146b 100644 --- a/worker/src/telegram_api/telegram.ts +++ b/worker/src/telegram_api/telegram.ts @@ -2,18 +2,17 @@ import { Context } from "hono"; import { Telegraf, Context as TgContext, Markup } from "telegraf"; import { callbackQuery } from "telegraf/filters"; -import { InputMediaDocument } from "telegraf/types"; import { CONSTANTS } from "../constants"; import { getBooleanValue, getDomains, getJsonObjectValue, getStringValue } from '../utils'; import { TelegramSettings } from "./settings"; +import { sendTelegramAttachments } from "./tg_file_upload"; import { bindTelegramAddress, deleteTelegramAddress, jwtListToAddressData, tgUserNewAddress, unbindTelegramAddress, unbindTelegramByAddress } from "./common"; import { commonParseMail } from "../common"; import { UserFromGetMe } from "telegraf/types"; import i18n from "../i18n"; import { LocaleMessages } from "../i18n/type"; -const TG_MAX_FILE_SIZE = 50 * 1024 * 1024; // 50MB Telegram Bot API limit // Helper to get messages by userId const getTgMessages = async ( @@ -438,32 +437,10 @@ export async function sendMailToTelegram( await bot.telegram.sendMessage(targetUserId, mail, { ...Markup.inlineKeyboard([...buttons]) }); - // send attachments - if (getBooleanValue(c.env.ENABLE_TG_PUSH_ATTACHMENT)) { - const validAttachments = attachments.filter(att => { - if (att.content.byteLength > TG_MAX_FILE_SIZE) { - console.log(`Skipping attachment ${att.filename}: ${(att.content.byteLength / 1024 / 1024).toFixed(1)}MB exceeds 50MB limit`); - return false; - } - return true; - }); - if (validAttachments.length > 0) { - const caption = `From: ${parsedEmailContext.parsedEmail?.sender || ""}\nSubject: ${parsedEmailContext.parsedEmail?.subject || ""}`; - const batchSize = 6; - for (let i = 0; i < validAttachments.length; i += batchSize) { - const batch = validAttachments.slice(i, i + batchSize); - try { - const mediaGroup: InputMediaDocument[] = batch.map((att, idx) => ({ - type: 'document', - media: { source: Buffer.from(att.content), filename: att.filename }, - ...(i === 0 && idx === 0 ? { caption } : {}), - })); - await bot.telegram.sendMediaGroup(targetUserId, mediaGroup); - } catch (e) { - console.error(`Failed to send attachment batch ${i / batchSize + 1}:`, e); - } - } - } + // send attachments via native fetch (telegraf multipart upload is incompatible with CF Workers) + if (getBooleanValue(c.env.ENABLE_TG_PUSH_ATTACHMENT) && attachments.length > 0) { + const caption = `From: ${parsedEmailContext.parsedEmail?.sender || ""}\nSubject: ${parsedEmailContext.parsedEmail?.subject || ""}`; + await sendTelegramAttachments(c.env.TELEGRAM_BOT_TOKEN, targetUserId, attachments, caption); } }; diff --git a/worker/src/telegram_api/tg_file_upload.ts b/worker/src/telegram_api/tg_file_upload.ts new file mode 100644 index 00000000..c20c429b --- /dev/null +++ b/worker/src/telegram_api/tg_file_upload.ts @@ -0,0 +1,49 @@ +const TG_MAX_FILE_SIZE = 50 * 1024 * 1024; // 50MB Telegram Bot API limit + +export async function sendTelegramAttachments( + botToken: string, + chatId: string, + attachments: ParsedEmailAttachment[], + caption: string +) { + try { + const validAttachments = attachments.filter(att => { + if (att.content.byteLength > TG_MAX_FILE_SIZE) { + console.log(`Skipping attachment ${att.filename}: ${(att.content.byteLength / 1024 / 1024).toFixed(1)}MB exceeds 50MB limit`); + return false; + } + return true; + }); + if (validAttachments.length === 0) return; + + const batchSize = 6; + for (let i = 0; i < validAttachments.length; i += batchSize) { + const batch = validAttachments.slice(i, i + batchSize); + const formData = new FormData(); + const media: { type: string; media: string; caption?: string }[] = []; + for (let j = 0; j < batch.length; j++) { + const att = batch[j]; + const attachKey = `file${j}`; + media.push({ + type: 'document', + media: `attach://${attachKey}`, + ...(i === 0 && j === 0 ? { caption } : {}), + }); + const blob = new Blob([att.content], { type: 'application/octet-stream' }); + formData.append(attachKey, blob, att.filename || `attachment_${j}`); + } + formData.append('chat_id', chatId); + formData.append('media', JSON.stringify(media)); + const res = await fetch( + `https://api.telegram.org/bot${botToken}/sendMediaGroup`, + { method: 'POST', body: formData } + ); + if (!res.ok) { + const text = await res.text(); + console.error(`Failed to send attachment batch ${i / batchSize + 1}: ${res.status} ${text.substring(0, 200)}`); + } + } + } catch (e) { + console.error("Failed to send telegram attachments:", e); + } +}