如何用Gmail API和C#实现邮件自动转发功能?
实现Gmail新邮件自动转发(C#)
核心修改点
- 扩展API权限,新增
GmailService.Scope.GmailReadonly和GmailModify,确保能读取邮件并修改状态 - 添加未读邮件查询逻辑
- 实现邮件转发的封装逻辑
- 新增邮件状态标记(标记为已读)避免重复处理
- 添加定时轮询机制
完整代码实现
using System; using System.IO; using Google.Apis.Auth.OAuth2; using Google.Apis.Gmail.v1; using Google.Apis.Gmail.v1.Data; using Google.Apis.Services; using Google.Apis.Util.Store; using System.Threading; using System.Threading.Tasks; using System.Linq; namespace GmailAutoForward { internal class Program { // 扩展权限:需要读取、修改、发送邮件 static string[] Scopes = { GmailService.Scope.GmailSend, GmailService.Scope.GmailReadonly, GmailService.Scope.GmailModify }; static string ApplicationName = "Gmail Auto Forwarder"; // 目标转发邮箱,替换为你的目标地址 static string ForwardToEmail = "target-email@gmail.com"; // 轮询间隔(毫秒,这里设为5分钟) static int PollingInterval = 300000; static async Task Main(string[] args) { // 初始化认证 UserCredential credential; using (var stream = new FileStream("credentials.json", FileMode.Open, FileAccess.Read)) { string credPath = "token_forward.json"; credential = await GoogleWebAuthorizationBroker.AuthorizeAsync( GoogleClientSecrets.FromStream(stream).Secrets, Scopes, "user", CancellationToken.None, new FileDataStore(credPath, true)); Console.WriteLine("认证文件已保存至: " + credPath); } // 创建Gmail服务实例 var service = new GmailService(new BaseClientService.Initializer() { HttpClientInitializer = credential, ApplicationName = ApplicationName, }); Console.WriteLine("邮件自动转发服务已启动,按Ctrl+C停止..."); while (true) { await ProcessUnreadEmails(service); await Task.Delay(PollingInterval); } } /// <summary> /// 处理所有未读邮件 /// </summary> private static async Task ProcessUnreadEmails(GmailService service) { try { // 查询未读邮件(只获取ID和基本信息) var listRequest = service.Users.Messages.List("me"); listRequest.Q = "is:unread"; listRequest.MaxResults = 10; // 每次最多处理10封,可调整 var messagesList = await listRequest.ExecuteAsync(); if (messagesList.Messages == null || messagesList.Messages.Count == 0) { Console.WriteLine($"{DateTime.Now}: 无未读邮件"); return; } Console.WriteLine($"{DateTime.Now}: 发现{messagesList.Messages.Count}封未读邮件,开始处理..."); foreach (var msg in messagesList.Messages) { // 获取完整邮件内容 var fullMsg = await service.Users.Messages.Get("me", msg.Id).ExecuteAsync(); // 转发邮件 await ForwardEmail(service, fullMsg); // 标记为已读 await MarkEmailAsRead(service, msg.Id); Console.WriteLine($"已转发并标记邮件ID {msg.Id} 为已读"); } } catch (Exception ex) { Console.WriteLine($"处理邮件时出错: {ex.Message}"); } } /// <summary> /// 转发指定邮件 /// </summary> private static async Task ForwardEmail(GmailService service, Message originalMsg) { // 解析原邮件主题,添加"FWD: "前缀 string originalSubject = GetHeaderValue(originalMsg.Payload.Headers, "Subject"); string forwardSubject = string.IsNullOrEmpty(originalSubject) ? "转发邮件" : $"FWD: {originalSubject}"; // 提取原邮件文本内容 string originalBody = GetEmailBody(originalMsg); // 构造转发邮件的原始内容 string rawContent = $"To: {ForwardToEmail}\r\n" + $"Subject: {forwardSubject}\r\n" + $"Content-Type: text/plain; charset=utf-8\r\n\r\n" + $"--- 原始邮件内容 ---\n\n{originalBody}"; // 编码并发送 var forwardMsg = new Message { Raw = Base64UrlEncode(rawContent) }; await service.Users.Messages.Send(forwardMsg, "me").ExecuteAsync(); } /// <summary> /// 标记邮件为已读 /// </summary> private static async Task MarkEmailAsRead(GmailService service, string messageId) { var modifyRequest = new ModifyMessageRequest { RemoveLabelIds = new[] { "UNREAD" } }; await service.Users.Messages.Modify(modifyRequest, "me", messageId).ExecuteAsync(); } /// <summary> /// 获取邮件头指定字段的值 /// </summary> private static string GetHeaderValue(IList<MessagePartHeader> headers, string name) { var header = headers?.FirstOrDefault(h => string.Equals(h.Name, name, StringComparison.OrdinalIgnoreCase)); return header?.Value; } /// <summary> /// 提取邮件文本内容(支持纯文本和多部分邮件) /// </summary> private static string GetEmailBody(Message msg) { // 处理纯文本邮件 if (msg.Payload.MimeType == "text/plain") { return string.IsNullOrEmpty(msg.Payload.Body.Data) ? "" : Base64UrlDecode(msg.Payload.Body.Data); } // 处理多部分邮件,查找纯文本部分 if (msg.Payload.Parts != null) { var plainTextPart = msg.Payload.Parts.FirstOrDefault(p => p.MimeType == "text/plain"); if (plainTextPart != null && !string.IsNullOrEmpty(plainTextPart.Body.Data)) { return Base64UrlDecode(plainTextPart.Body.Data); } } return "无法提取邮件内容"; } /// <summary> /// Base64URL编码 /// </summary> private static string Base64UrlEncode(string input) { var inputBytes = System.Text.Encoding.UTF8.GetBytes(input); return Convert.ToBase64String(inputBytes) .Replace('+', '-') .Replace('/', '_') .Replace("=", ""); } /// <summary> /// Base64URL解码 /// </summary> private static string Base64UrlDecode(string input) { input = input.Replace('-', '+').Replace('_', '/'); // 补全缺失的等号 switch (input.Length % 4) { case 2: input += "=="; break; case 3: input += "="; break; } var outputBytes = Convert.FromBase64String(input); return System.Text.Encoding.UTF8.GetString(outputBytes); } } }
关键说明
- 权限调整:必须添加
GmailReadonly和GmailModify权限,否则无法读取未读邮件和标记状态 - 轮询机制:代码中设置为5分钟轮询一次,可根据需求修改
PollingInterval的值 - 邮件内容处理:支持纯文本和多类型邮件的文本内容提取,如需转发HTML内容,可修改
GetEmailBody和转发内容的MIME类型 - 重复处理避免:转发后立即标记邮件为已读,确保同一封邮件不会被重复转发
- 错误处理:添加基础异常捕获,避免单个邮件处理失败导致整个服务停止
内容的提问来源于stack exchange,提问作者Cyn
相关产品推荐
相关产品推荐

