将BigQuery循环查询结果嵌入Python smtplib邮件正文报错求助
解决方法:让函数返回邮件正文内容,而非仅打印
这个错误的根源很明确:你的query_named_params函数没有返回任何值(默认返回None),但smtplib.SMTP.sendmail()的第三个参数需要是一个字符串格式的邮件内容,它尝试计算None的长度时就触发了TypeError。
我们需要调整两个核心部分:
1. 修改查询函数,让它返回格式化后的结果字符串
把原来直接print的逻辑改成收集结果到一个字符串里,最后返回这个字符串:
def query_named_params(corpus, min_word_count): client = bigquery.Client() query = """ SELECT word, word_count FROM `bigquery-public-data.samples.shakespeare` WHERE corpus = @corpus AND word_count >= @min_word_count ORDER BY word_count DESC; """ query_params = [ bigquery.ScalarQueryParameter('corpus', 'STRING', 'sonnets'), bigquery.ScalarQueryParameter('min_word_count', 'INT64', 10) ] job_config = bigquery.QueryJobConfig() job_config.query_parameters = query_params query_job = client.query(query, job_config=job_config) # 收集结果到字符串,而不是直接打印 result_text = "莎士比亚十四行诗中出现次数≥10的单词:\n\n" for row in query_job.result(): # 直接用query_job.result()更简洁,不用再获取表 result_text += "{} : {} 次\n".format(row.word, row.word_count) return result_text # 返回结果字符串
这里我还简化了获取结果的逻辑,直接用query_job.result()遍历行,比先获取目标表再list_rows更高效。
2. 构建完整的邮件内容(包含主题头)
纯文本邮件需要加上Subject头,不然收件方看到的邮件会没有主题。我们先获取查询结果,再拼接成完整的邮件内容:
# --------------------EMAIL PORTION -------------# print('Starting email send...') server = smtplib.SMTP('smtp.gmail.com', 587) server.starttls() server.login(login_email, login_pwd) # 获取查询结果文本 query_result = query_named_params('corpus', 'min_word_count') # 构建完整邮件内容,添加主题 msg = """Subject: BigQuery 莎士比亚数据查询结果 {} """.format(query_result) # 发送邮件,传入正确的邮件内容字符串 server.sendmail(login_email, recipients, msg) server.quit()
完整修改后的代码
from google.cloud import bigquery import smtplib # Variables login_email = 'MYEMAIL' login_pwd = 'MYPASSWORD' recipients = 'EMAILSENDINGTO' # Create a function def query_named_params(corpus, min_word_count): client = bigquery.Client() query = """ SELECT word, word_count FROM `bigquery-public-data.samples.shakespeare` WHERE corpus = @corpus AND word_count >= @min_word_count ORDER BY word_count DESC; """ query_params = [ bigquery.ScalarQueryParameter('corpus', 'STRING', 'sonnets'), bigquery.ScalarQueryParameter('min_word_count', 'INT64', 10) ] job_config = bigquery.QueryJobConfig() job_config.query_parameters = query_params query_job = client.query(query, job_config=job_config) # 收集结果为字符串 result_text = "莎士比亚十四行诗中出现次数≥10的单词:\n\n" for row in query_job.result(): result_text += "{} : {} 次\n".format(row.word, row.word_count) return result_text # --------------------EMAIL PORTION -------------# print('Starting email send...') server = smtplib.SMTP('smtp.gmail.com', 587) server.starttls() server.login(login_email, login_pwd) # 获取查询结果并构建邮件 query_result = query_named_params('corpus', 'min_word_count') msg = """Subject: BigQuery 莎士比亚数据查询结果 {} """.format(query_result) server.sendmail(login_email, recipients, msg) server.quit() if __name__ == '__main__': # 测试查询函数(可选) print(query_named_params('corpus','min_word_count'))
额外注意事项
- 如果你的Gmail账号开启了两步验证,需要用应用专用密码代替原密码登录,不然会触发登录失败。
- 确保你的Python环境已经正确安装
google-cloud-bigquery库,并且配置了BigQuery的认证凭据(比如环境变量或密钥文件)。
内容的提问来源于stack exchange,提问作者Jeff
相关产品推荐
相关产品推荐

