在C#中发送带按钮的邮件:实现审批/驳回功能适配Gmail与Outlook
邮件内审批/驳回按钮兼容Gmail和Outlook的C#实现思路
方案一:通用HTML链接按钮(全客户端兼容)
这是最稳妥的方案,Gmail和Outlook都原生支持HTML邮件中的链接按钮,无需依赖特定客户端的扩展功能。
核心思路
- 后端API准备:暴露两个接口分别处理审批和驳回请求,比如:
POST/GET https://yourdomain.com/api/approval/approvePOST/GET https://yourdomain.com/api/approval/reject
每个请求携带唯一的requestId标识审批项,同时添加签名参数(如HMAC生成的签名)防止恶意篡改。
- 构造HTML邮件:用带内联样式的
<a>标签模拟按钮样式,链接到上述API。邮件客户端不支持外部样式表,所有样式必须写在标签内。 - C#发送邮件:使用MailKit(推荐,比原生
System.Net.Mail更灵活)或MailMessage构造HTML格式的邮件并发送。
C#代码示例(用MailKit)
using MailKit.Net.Smtp; using MimeKit; var requestId = "unique-approval-request-001"; // 生成带签名的API链接(示例签名需替换为实际HMAC逻辑) var signature = GenerateHmacSignature(requestId, "your-secret-key"); var approveUrl = $"https://yourdomain.com/api/approval/approve?requestId={requestId}&signature={signature}"; var rejectUrl = $"https://yourdomain.com/api/approval/reject?requestId={requestId}&signature={signature}"; var message = new MimeMessage(); message.From.Add(new MailboxAddress("审批系统", "approval@yourdomain.com")); message.To.Add(new MailboxAddress("审批人", "approver@example.com")); message.Subject = "请审批:XX项目申请"; var bodyBuilder = new BodyBuilder(); bodyBuilder.HtmlBody = $@" <p>您好,请处理以下审批申请:</p> <p>申请ID:{requestId}</p> <p> <a href=""{approveUrl}"" style=""background: #28a745; border: none; color: white; padding: 12px 24px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; border-radius: 4px; margin-right: 10px;"">批准(Approve)</a> <a href=""{rejectUrl}"" style=""background: #dc3545; border: none; color: white; padding: 12px 24px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; border-radius: 4px;"">驳回(Reject)</a> </p>"; message.Body = bodyBuilder.ToMessageBody(); // 发送邮件 using var client = new SmtpClient(); client.Connect("smtp.yourdomain.com", 587, false); client.Authenticate("smtp-username", "smtp-password"); client.Send(message); client.Disconnect(true); // 辅助方法:生成HMAC签名 string GenerateHmacSignature(string requestId, string secretKey) { using var hmac = new System.Security.Cryptography.HMACSHA256(System.Text.Encoding.UTF8.GetBytes(secretKey)); var hashBytes = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(requestId)); return Convert.ToBase64String(hashBytes); }
方案二:Outlook原生按钮+Gmail降级方案
如果希望Outlook用户获得更原生的体验(按钮在邮件内直接触发请求,无需跳转浏览器),可以结合Outlook的Actionable Messages,同时给Gmail显示普通链接按钮。
核心思路
- Outlook Actionable Messages配置:在邮件中嵌入JSON-LD格式的Actionable Messages定义,Outlook会识别并显示原生按钮。需要提前在Microsoft 365后台验证你的域名,否则按钮会跳转到浏览器。
- Gmail降级处理:Gmail不支持Actionable Messages,因此同时保留HTML链接按钮,Gmail会自动忽略JSON-LD脚本,显示普通按钮。
- 后端API适配:支持POST请求(Actionable Messages默认用POST),并处理CORS(Outlook客户端会直接发起跨域请求)。
C#代码示例(添加Actionable Messages)
// 延续方案一的邮件构造逻辑,修改HtmlBody部分 bodyBuilder.HtmlBody = $@" <p>您好,请处理以下审批申请:</p> <p>申请ID:{requestId}</p> <!-- Gmail显示的普通按钮 --> <p> <a href=""{approveUrl}"" style=""background: #28a745; border: none; color: white; padding: 12px 24px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; border-radius: 4px; margin-right: 10px;"">批准(Approve)</a> <a href=""{rejectUrl}"" style=""background: #dc3545; border: none; color: white; padding: 12px 24px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; border-radius: 4px;"">驳回(Reject)</a> </p> <!-- Outlook识别的Actionable Messages --> <script type=""application/ld+json""> {{ ""@context"": ""http://schema.org"", ""@type"": ""EmailMessage"", ""potentialAction"": [ {{ ""@type"": ""HttpActionHandler"", ""name"": ""批准"", ""url"": ""https://yourdomain.com/api/approval/approve"", ""method"": ""POST"", ""body"": ""{{\""requestId\"":\""{requestId}\""}}"", ""headers"": [{{""Content-Type"": ""application/json""}}] }}, {{ ""@type"": ""HttpActionHandler"", ""name"": ""驳回"", ""url"": ""https://yourdomain.com/api/approval/reject"", ""method"": ""POST"", ""body"": ""{{\""requestId\"":\""{requestId}\""}}"", ""headers"": [{{""Content-Type"": ""application/json""}}] }} ], ""description"": ""请审批该项目申请"" }} </script>";
关键注意事项
- 安全防护:必须对请求参数签名,防止恶意用户伪造审批请求;后端需验证签名和
requestId的合法性,同时保证接口幂等(避免同一请求重复执行)。 - 样式兼容性:所有CSS样式必须用内联方式写在标签内,避免使用类选择器或外部样式表,大部分邮件客户端不支持这些特性。
- Outlook域名验证:使用Actionable Messages时,需在Microsoft 365 Admin Center验证你的发件域名,否则按钮会强制跳转浏览器。
内容的提问来源于stack exchange,提问作者manthan
相关产品推荐
相关产品推荐

