
上一篇我們聊了怎麼用 AI 處理商業信件的五個常見場景。但如果每封信都要開 ChatGPT、貼 prompt、再複製回 Gmail,省下的時間又被操作流程吃掉了。
這篇直接教你把 AI 裝進 Gmail 裡。打開任何一封信,按一下按鈕,AI 就自動讀取信件內容、幫你草擬回覆,直接開在回覆框裡。確認沒問題就寄出,整個流程不到 30 秒。
不用裝 Chrome 擴充功能、不用付月費、不用寫程式。用的是 Google 自家的 Apps Script,搭配 Gemini AI,完全免費。
只要兩樣:
下方填入你的 Gemini API Key 和公司名稱,程式碼會自動幫你帶入。然後照著三個步驟操作就好。
{
"timeZone": "Asia/Taipei",
"dependencies": {},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"addOns": {
"common": {
"name": "AI 信件助手",
"logoUrl": "https://www.gstatic.com/images/icons/material/system/1x/smart_toy_black_24dp.png",
"layoutProperties": {
"primaryColor": "#2377FC"
}
},
"gmail": {
"contextualTriggers": [
{
"unconditional": {},
"onTriggerFunction": "onGmailMessageOpen"
}
]
}
},
"oauthScopes": [
"https://www.googleapis.com/auth/gmail.addons.execute",
"https://www.googleapis.com/auth/gmail.addons.current.message.readonly",
"https://www.googleapis.com/auth/gmail.modify",
"https://www.googleapis.com/auth/script.external_request"
]
}// ============================================================
// Gmail AI 一鍵回覆 — Google Apps Script
// 在 Gmail 側邊欄加入「AI 草擬回覆」按鈕
// 使用 Gemini API 自動讀取信件內容並生成回覆草稿
// ============================================================
// ── 設定區 ─────────────────────────────────────────────────
const CONFIG = {
GEMINI_API_KEY: "在這裡貼上你的 Gemini API Key",
MODEL: "gemini-2.5-flash",
COMPANY_NAME: "你的公司名稱",
DEFAULT_TONE: "專業但親切,用『我們』而不是『本公司』,不用『敬啟者』等過於正式的稱呼",
};
// ── 場景預設 ───────────────────────────────────────────────
const SCENES = {
auto: {
label: "自動判斷",
instruction: "請根據信件內容自動判斷最適合的回覆方式",
},
complaint: {
label: "客訴回覆",
instruction:
"這是一封客訴信。回覆時請先表達同理心、承認對方的不便,再說明具體的處理方式。不要推卸責任,語氣要讓對方感覺被重視",
},
followup: {
label: "客戶跟進",
instruction:
"這是一封跟進信,對方之前聯絡過但還沒回覆。語氣要輕鬆自然、不要有壓力感。給對方一個「順便回覆」的理由,不要用「不知道您是否有空」這種太客氣的說法。結尾提供一個具體的下一步",
},
decline: {
label: "婉拒合作",
instruction:
"需要婉拒對方的提議或合作邀約。語氣真誠、不卑不亢,讓對方覺得被尊重而不是被敷衍。保留未來合作的可能性,但不要過度承諾",
},
thankyou: {
label: "結案感謝",
instruction:
"專案或合作已經結束,這是一封感謝信。感謝要具體(提到合作中對方做得好的地方),不要只說「感謝合作」。結尾自然地提到未來還能合作的方向",
},
};
// ── 側邊欄入口 ─────────────────────────────────────────────
function onGmailMessageOpen(e) {
const card = CardService.newCardBuilder()
.setHeader(
CardService.newCardHeader()
.setTitle("AI 信件助手")
.setSubtitle("讓 AI 幫你草擬回覆")
.setImageUrl("https://www.gstatic.com/images/icons/material/system/1x/smart_toy_black_24dp.png")
)
.addSection(buildSceneSection())
.addSection(buildActionSection())
.build();
return [card];
}
function buildSceneSection() {
const sceneDropdown = CardService.newSelectionInput()
.setType(CardService.SelectionInputType.DROPDOWN)
.setFieldName("scene")
.setTitle("回覆場景");
let isFirst = true;
for (const key in SCENES) {
sceneDropdown.addItem(SCENES[key].label, key, isFirst);
isFirst = false;
}
const toneDropdown = CardService.newSelectionInput()
.setType(CardService.SelectionInputType.DROPDOWN)
.setFieldName("tone")
.setTitle("語氣風格")
.addItem("專業親切", "專業但親切,用詞溫和不冷冰冰", true)
.addItem("正式商務", "正式的商務語氣,用詞嚴謹", false)
.addItem("輕鬆友善", "輕鬆自然的語氣,像朋友之間的對話", false)
.addItem("簡短直接", "簡短有力,不廢話,直接講重點", false);
return CardService.newCardSection()
.addWidget(sceneDropdown)
.addWidget(toneDropdown)
.addWidget(
CardService.newTextInput()
.setFieldName("extra_instruction")
.setTitle("補充指示(選填)")
.setHint("例如:可以提供全額退款、請對方約下週開會")
);
}
function buildActionSection() {
return CardService.newCardSection().addWidget(
CardService.newButtonSet()
.addButton(
CardService.newTextButton()
.setText("✨ AI 草擬回覆")
.setComposeAction(
CardService.newAction().setFunctionName("onDraftReply"),
CardService.ComposedEmailType.REPLY_AS_DRAFT
)
.setTextButtonStyle(CardService.TextButtonStyle.FILLED)
)
.addButton(
CardService.newTextButton()
.setText("📋 AI 摘要")
.setOnClickAction(
CardService.newAction().setFunctionName("onSummarize")
)
.setTextButtonStyle(CardService.TextButtonStyle.TEXT)
)
);
}
// ── 核心功能:AI 草擬回覆 ──────────────────────────────────
function onDraftReply(e) {
try {
const messageId = e.gmail.messageId;
const message = GmailApp.getMessageById(messageId);
const thread = message.getThread();
const senderName = extractName(message.getFrom());
const subject = message.getSubject();
const body = extractPlainText(message);
const sceneKey = e.formInput.scene || "auto";
const scene = SCENES[sceneKey] || SCENES.auto;
const tone = e.formInput.tone || CONFIG.DEFAULT_TONE;
const extraInstruction = e.formInput.extra_instruction || "";
const prompt = buildReplyPrompt(senderName, subject, body, scene, tone, extraInstruction);
const aiReply = callGemini(prompt);
const cleanReply = aiReply
.replace(/\*\*(.*?)\*\*/g, "$1")
.replace(/\*(.*?)\*/g, "$1")
.replace(/^#+\s*/gm, "")
.replace(/^[-*]\s+/gm, "・")
.trim();
const draft = thread.createDraftReply(cleanReply);
return CardService.newComposeActionResponseBuilder()
.setGmailDraft(draft)
.build();
} catch (error) {
return CardService.newActionResponseBuilder()
.setNotification(
CardService.newNotification().setText("❌ 發生錯誤:" + error.message)
)
.build();
}
}
// ── 附加功能:AI 信件摘要 ──────────────────────────────────
function onSummarize(e) {
try {
const messageId = e.gmail.messageId;
const message = GmailApp.getMessageById(messageId);
const body = extractPlainText(message);
const prompt =
"請用繁體中文,用 3 到 5 個重點摘要以下這封信的內容。" +
"每個重點用一句話講完。如果信中有需要回覆或處理的事項,請特別標註。\n\n" +
"信件內容:\n" + body;
const summary = callGemini(prompt);
const card = CardService.newCardBuilder()
.setHeader(CardService.newCardHeader().setTitle("📋 信件摘要"))
.addSection(
CardService.newCardSection().addWidget(
CardService.newTextParagraph().setText(summary)
)
)
.addSection(buildActionSection())
.build();
return CardService.newActionResponseBuilder()
.setNavigation(CardService.newNavigation().pushCard(card))
.build();
} catch (error) {
return CardService.newActionResponseBuilder()
.setNotification(
CardService.newNotification().setText("❌ 發生錯誤:" + error.message)
)
.build();
}
}
// ── Gemini API 呼叫 ────────────────────────────────────────
function callGemini(prompt) {
const url =
"https://generativelanguage.googleapis.com/v1beta/models/" +
CONFIG.MODEL +
":generateContent?key=" +
CONFIG.GEMINI_API_KEY;
const payload = {
contents: [{ parts: [{ text: prompt }] }],
generationConfig: {
temperature: 0.7,
maxOutputTokens: 8192,
},
};
const options = {
method: "post",
contentType: "application/json",
payload: JSON.stringify(payload),
muteHttpExceptions: true,
};
const response = UrlFetchApp.fetch(url, options);
const data = JSON.parse(response.getContentText());
if (data.error) {
throw new Error(data.error.message);
}
if (!data.candidates || !data.candidates[0]) {
throw new Error("Gemini 沒有回傳內容,請稍後再試");
}
const candidate = data.candidates[0];
const fullText = candidate.content.parts.map(function(p) { return p.text || ""; }).join("");
return fullText;
}
// ── Prompt 組合 ────────────────────────────────────────────
function buildReplyPrompt(senderName, subject, body, scene, tone, extraInstruction) {
let prompt =
"你是「" + CONFIG.COMPANY_NAME + "」的信件助理。" +
"請根據以下收到的信件,用繁體中文草擬一封回覆。\n\n" +
"【回覆場景】\n" +
scene.instruction + "\n\n" +
"【回覆規則】\n" +
"・語氣:" + tone + "\n" +
"・長度:200 到 300 字,完整但不囉唆\n" +
"・不要加主旨,只寫信件內文\n" +
"・不要加「敬啟者」「此致敬禮」等過於正式的用語\n" +
"・開頭直接稱呼對方名字\n" +
"・不要使用 markdown 格式,純文字即可\n";
if (extraInstruction) {
prompt += "・補充指示:" + extraInstruction + "\n";
}
prompt +=
"\n【收到的信件】\n" +
"寄件人:" + senderName + "\n" +
"主旨:" + subject + "\n" +
"內容:\n" + body;
return prompt;
}
// ── 工具函式 ───────────────────────────────────────────────
function extractName(from) {
const match = from.match(/^"?(.+?)"?\s*<.*>$/);
return match ? match[1].trim() : from.split("@")[0];
}
function extractPlainText(message) {
let body = message.getPlainBody();
if (!body || body.trim().length === 0) {
body = message.getBody().replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
}
if (body.length > 3000) {
body = body.substring(0, 3000) + "\n...(內容過長,已截斷)";
}
return body;
}打開 Gmail,點開任何一封信。右邊側邊欄會出現「AI 信件助手」的圖示,點開它:
AI 會讀取信件內容,幾秒鐘後直接在回覆框裡產生草稿。你看過沒問題,按寄出就好。
如果只想快速了解一封長信在講什麼,按「AI 摘要」就會列出 3-5 個重點。
信件內容只會傳給 Google 的 Gemini API 處理,不會經過任何第三方伺服器。這跟你直接在 Google AI Studio 裡貼文字是一樣的。
Gemini API 有免費額度,一般日常使用完全夠用。除非你一天回覆上百封信,否則不會碰到付費門檻。
建議還是看過再寄。AI 生成的是草稿,幫你跳過「從零開始想措辭」的痛苦。花兩分鐘微調細節和語氣,比自己從頭寫快得多。






