如何用Python Google Cloud Function每日定时发送Gmail邮件?
最简实现:定时触发Google Cloud Function发送Gmail邮件
Hey there! Let's break down the simplest, most reliable way to set up a daily scheduled email from a Google Cloud Function to a Gmail address. First, let's cover why your initial attempts might have hit snags, then jump into the working solution.
为什么之前的方案可能失败?
- 方案1(smtplib): 现在Gmail已经不再支持大多数账号使用明文密码登录了。你需要启用双因素认证后生成应用专用密码,或者开启“不太安全的应用访问”(不推荐,且Google正在逐步淘汰该功能)。另外,在函数里硬编码凭证也是严重的安全风险。
- 方案2(SendGrid): 大概率是API密钥配置出了问题——你注释掉了从环境变量读取密钥的代码,硬编码的密钥可能无效,或者SendGrid控制台里的发件邮箱未完成验证。
最优方案:GCP生态内实现(Gmail API + Cloud Scheduler)
这个方案用Google原生工具实现,更安全、易扩展,还能避免依赖第三方服务。以下是分步指南:
1. 前置准备
- 在你的GCP项目中启用Gmail API、Cloud Functions API和Cloud Scheduler API。
- 创建一个服务账号,给它分配
Gmail Send权限(测试阶段可以用Editor,但生产环境要严格限制权限)。 - 如果是用个人Gmail账号发送:需要配置域范围授权(仅适用于Google Workspace账号),或者使用OAuth2.0刷新令牌。为了简化,这里我们推荐用Google Workspace服务账号;如果是个人账号,可以用应用专用密码替代(下文会给出示例)。
2. Cloud Function代码(Python)
这段代码用Gmail API发送邮件,凭证从GCP Secret Manager加载(也可以用环境变量,但Secret Manager更安全)。
import base64 from googleapiclient.discovery import build from google.oauth2 import service_account def send_daily_email(event, context): # 加载服务账号凭证(将JSON密钥文件存储在Secret Manager中!) credentials = service_account.Credentials.from_service_account_file( 'path/to/service-account-key.json', scopes=['https://www.googleapis.com/auth/gmail.send'] ) # 将凭证委托给发件邮箱(仅适用于Workspace账号) delegated_credentials = credentials.with_subject('your-sender-email@example.com') # 构建Gmail API客户端 service = build('gmail', 'v1', credentials=delegated_credentials) # 构造邮件内容 to_email = 'recipient-email@gmail.com' subject = '每日定时邮件' body = '这是来自Google Cloud Function的每日自动邮件!' # 按RFC 2822格式组装邮件 message = f"""From: 发件人 <your-sender-email@example.com> To: 收件人 <{to_email}> Subject: {subject} {body} """ # 编码邮件以适配Gmail API要求 encoded_message = base64.urlsafe_b64encode(message.encode('utf-8')).decode('utf-8') create_message = {'raw': encoded_message} # 发送邮件 try: send_message = service.users().messages().send(userId='me', body=create_message).execute() print(f"邮件发送成功!消息ID: {send_message['id']}") return "邮件发送成功" except Exception as e: print(f"发送邮件出错: {e}") return f"邮件发送失败: {str(e)}"
3. 配置Cloud Scheduler
- 打开GCP控制台的Cloud Scheduler页面。
- 创建新任务:
- 频率: 使用 cron 表达式,比如
0 0 * * *(每天UTC时间午夜触发,可根据你的时区调整)。 - 目标: 选择
HTTP,填入你的Cloud Function的URL。 - HTTP方法: 选择
POST(Cloud Function默认期望POST触发)。 - 认证: 选择
添加OIDC令牌,并指定你之前创建的服务账号。
- 频率: 使用 cron 表达式,比如
个人Gmail账号适配方案(smtplib + 应用专用密码)
如果你用的是个人Gmail账号,开启双因素认证后生成应用专用密码,就可以用smtplib实现,记得把密码存在Secret Manager里:
import smtplib from google.cloud import secretmanager def send_email_smtp(event, context): # 从Secret Manager加载应用专用密码 client = secretmanager.SecretManagerServiceClient() secret_name = "projects/你的项目ID/secrets/gmail-app-password/versions/latest" response = client.access_secret_version(request={"name": secret_name}) app_password = response.payload.data.decode("UTF-8") gmail_user = 'your-email@gmail.com' to = ['recipient-email@gmail.com'] subject = '每日测试邮件' body = '这是通过smtplib + 应用专用密码发送的邮件' email_text = f"""From: {gmail_user} To: {', '.join(to)} Subject: {subject} {body} """ try: server = smtplib.SMTP_SSL('smtp.gmail.com', 465) server.login(gmail_user, app_password) server.sendmail(gmail_user, to, email_text) server.close() print('邮件发送成功!') return "操作成功" except Exception as e: print(f"出错了: {e}") return "操作失败"
总结
最健壮且贴合GCP生态的方式是用Gmail API配合服务账号(Workspace)或应用专用密码(个人账号),再用Cloud Scheduler触发函数。这种方式无需依赖第三方服务,还能保证凭证的安全性。
内容的提问来源于stack exchange,提问作者abgo2020




