使用 python 在 Gmail 中发送邮件
Send mail in Gmail with python
我正在尝试使用 Gmail API 发送一封简单的测试电子邮件,但对于我找到的每个代码示例,我总是收到相同的错误。
我现在的代码是这样的:
def validationService():
SCOPES = ['https://mail.google.com/']
SERVICE_ACCOUNT_FILE = 'creds.json'
creds = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)
service = build('gmail', 'v1', credentials=creds)
return service
def SendMessage(service, user_id, message):
try:
message = (service.users().messages().send(userId=user_id, body=message).execute())
print('Message Id:',message['id'])
return message
except errors.HttpError as error:
print('An error occurred:', error)
def CreateMessage(sender, to, subject, message_text):
message = MIMEText(message_text)
message['to'] = to
message['from'] = sender
message['subject'] = subject
return {'raw': base64.urlsafe_b64encode(message.as_string().encode()).decode()}
service = validationService()
email = CreateMessage("sendermail@gmail.com", "receiverrmail@gmail.com", "Test", "This is a test")
sent = SendMessage(service, "sendermail@gmail.com", email)
Returns
>>> An error occurred: <HttpError 400 when requesting https://www.googleapis.com/gmail/v1/users/me/messages/send?alt=json returned "Bad Request">
我也不明白 CreateMessage 中的 "sender" 参数和 SendMessage 中的 userId 之间的区别。
如果有用,我正在使用服务帐户凭据
-
谢谢!
使用 service account with the Gmail API. You need to set domain-wide delegation, which allows the service account to impersonate any user in your G Suite domain 时。因此,您必须拥有 G Suite 帐户才能使用域范围授权,如文档所述:
If you have a G Suite domain—if you use G Suite, for example—an
administrator of the G Suite domain can authorize an application to
access user data on behalf of users in the G Suite domain.
那么现在,为什么需要冒充用户(真人)?这是因为服务帐户是一个机器人(不是真人),用于服务器到服务器的交互,使您的应用程序调用成为可能 Google APIs,尽管服务帐户有名为 client_email
的参数,其结构类似于 name@project-randomnumber.iam.gserviceaccount.com
,它不是属于真人的真实电子邮件(我知道这有点令人困惑)。
话虽如此,我对您的代码进行了一些更改。首先,我修改了您的 validationService
函数,以便使用全域委托构建服务。
def validationService():
# Set the crendentials
credentials = service_account.Credentials.\
from_service_account_file(SERVICE_ACCOUNT_FILE, scopes= SCOPES)
# Delegate the credentials to the user you want to impersonate
delegated_credentials = credentials.with_subject(USER_EMAIL)
service = discovery.build('gmail', 'v1', credentials=delegated_credentials)
return service
在你的SendMessage
函数中不一定要传递要发送邮件的用户。使用 me 就足够了 Users.messages: send Parameters 状态:
userId string The user's email address. The special value me can be
used to indicate the authenticated user.
def SendMessage(service, message):
message = service.users().messages().send(userId="me", body=message).execute()
return message
您最后的整个代码可能如下所示:
from googleapiclient import discovery, errors
from oauth2client import file, client, tools
from google.oauth2 import service_account
from email.mime.text import MIMEText
import base64
SERVICE_ACCOUNT_FILE = 'service_account.json'
SCOPES = [' https://mail.google.com/']
# The user we want to "impersonate"
USER_EMAIL = "user@domain"
def validationService():
# Set the crendentials
credentials = service_account.Credentials.\
from_service_account_file(SERVICE_ACCOUNT_FILE, scopes= SCOPES)
# Delegate the credentials to the user you want to impersonate
delegated_credentials = credentials.with_subject(USER_EMAIL)
service = discovery.build('gmail', 'v1', credentials=delegated_credentials)
return service
def SendMessage(service, message):
message = service.users().messages().send(userId="me", body=message).execute()
return message
def CreateMessage(sender, to, subject, message_text):
message = MIMEText(message_text)
message['to'] = to
message['from'] = sender
message['subject'] = subject
return {'raw': base64.urlsafe_b64encode(message.as_string().encode()).decode()}
def main():
try:
service = validationService()
email = CreateMessage(USER_EMAIL, "receiverrmail@domain", "Test", "This is a test")
email_sent = SendMessage(service, email)
print('Message Id:', email_sent['id'])
except errors.HttpError as err:
print('\n---------------You have the following error-------------')
print(err)
print('---------------You have the following error-------------\n')
if __name__ == '__main__':
main()
通知
您还需要通过在您的 G Suite 帐户上设置 Managing API client access 来允许您的服务帐户访问 Google 的 API。
您不会伤脑筋...只需使用电子邮件和 smtplib 库即可。如果您问我,通过 Python 发送电子邮件非常简单有趣。我在下面给出了我的代码,您应该基于此开发自己的代码。如果有效,请告诉我 - 我会很高兴。在这里....
import email, smtplib, os, time, fnmatch
from datetime import date, timedelta
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
def sendMailTo(recepient_id, today):
login_id = 'myemailID@gmail.com'
login_pwd = "mypassword"
fro_ = login_id
s_name = 'smtp.gmail.com'
s_port = 587
fileList = []
fi_type = '*.pdf'
file_path = "C:\Myfolder\Subfolder"
srvr = smtplib.SMTP(s_name, s_port)
srvr.ehlo()
srvr.starttls()
srvr.ehlo()
srvr.login(login_id, login_pwd)
sub = "Your subject here"
# loading MIMEMultipart obj onto outer var
outer = MIMEMultipart('alternative')
outer["From"] = 'Your company/Personal Name'
outer["To"] = recepient_id
outer['Subject'] = sub
# storing only pdf files
fileList = fnmatch.filter(os.listdir(file_path), fi_type)
for fi in fileList:
fi_name = os.path.join(file_path, fi)
fp = open(fi_name, 'rb')
img = MIMEImage(fp.read(), _subtype='jpg')
fp.close()
img.add_header('Content-disposition', "attachment", filename = fi)
outer.attach(img)
#start sending email with attachment with original file name
srvr.sendmail(fro_, recepient_id, outer.as_string())
part = None
outer = None
srvr.quit()
我正在尝试使用 Gmail API 发送一封简单的测试电子邮件,但对于我找到的每个代码示例,我总是收到相同的错误。
我现在的代码是这样的:
def validationService():
SCOPES = ['https://mail.google.com/']
SERVICE_ACCOUNT_FILE = 'creds.json'
creds = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)
service = build('gmail', 'v1', credentials=creds)
return service
def SendMessage(service, user_id, message):
try:
message = (service.users().messages().send(userId=user_id, body=message).execute())
print('Message Id:',message['id'])
return message
except errors.HttpError as error:
print('An error occurred:', error)
def CreateMessage(sender, to, subject, message_text):
message = MIMEText(message_text)
message['to'] = to
message['from'] = sender
message['subject'] = subject
return {'raw': base64.urlsafe_b64encode(message.as_string().encode()).decode()}
service = validationService()
email = CreateMessage("sendermail@gmail.com", "receiverrmail@gmail.com", "Test", "This is a test")
sent = SendMessage(service, "sendermail@gmail.com", email)
Returns
>>> An error occurred: <HttpError 400 when requesting https://www.googleapis.com/gmail/v1/users/me/messages/send?alt=json returned "Bad Request">
我也不明白 CreateMessage 中的 "sender" 参数和 SendMessage 中的 userId 之间的区别。
如果有用,我正在使用服务帐户凭据
- 谢谢!
使用 service account with the Gmail API. You need to set domain-wide delegation, which allows the service account to impersonate any user in your G Suite domain 时。因此,您必须拥有 G Suite 帐户才能使用域范围授权,如文档所述:
If you have a G Suite domain—if you use G Suite, for example—an administrator of the G Suite domain can authorize an application to access user data on behalf of users in the G Suite domain.
那么现在,为什么需要冒充用户(真人)?这是因为服务帐户是一个机器人(不是真人),用于服务器到服务器的交互,使您的应用程序调用成为可能 Google APIs,尽管服务帐户有名为 client_email
的参数,其结构类似于 name@project-randomnumber.iam.gserviceaccount.com
,它不是属于真人的真实电子邮件(我知道这有点令人困惑)。
话虽如此,我对您的代码进行了一些更改。首先,我修改了您的 validationService
函数,以便使用全域委托构建服务。
def validationService():
# Set the crendentials
credentials = service_account.Credentials.\
from_service_account_file(SERVICE_ACCOUNT_FILE, scopes= SCOPES)
# Delegate the credentials to the user you want to impersonate
delegated_credentials = credentials.with_subject(USER_EMAIL)
service = discovery.build('gmail', 'v1', credentials=delegated_credentials)
return service
在你的SendMessage
函数中不一定要传递要发送邮件的用户。使用 me 就足够了 Users.messages: send Parameters 状态:
userId string The user's email address. The special value me can be used to indicate the authenticated user.
def SendMessage(service, message):
message = service.users().messages().send(userId="me", body=message).execute()
return message
您最后的整个代码可能如下所示:
from googleapiclient import discovery, errors
from oauth2client import file, client, tools
from google.oauth2 import service_account
from email.mime.text import MIMEText
import base64
SERVICE_ACCOUNT_FILE = 'service_account.json'
SCOPES = [' https://mail.google.com/']
# The user we want to "impersonate"
USER_EMAIL = "user@domain"
def validationService():
# Set the crendentials
credentials = service_account.Credentials.\
from_service_account_file(SERVICE_ACCOUNT_FILE, scopes= SCOPES)
# Delegate the credentials to the user you want to impersonate
delegated_credentials = credentials.with_subject(USER_EMAIL)
service = discovery.build('gmail', 'v1', credentials=delegated_credentials)
return service
def SendMessage(service, message):
message = service.users().messages().send(userId="me", body=message).execute()
return message
def CreateMessage(sender, to, subject, message_text):
message = MIMEText(message_text)
message['to'] = to
message['from'] = sender
message['subject'] = subject
return {'raw': base64.urlsafe_b64encode(message.as_string().encode()).decode()}
def main():
try:
service = validationService()
email = CreateMessage(USER_EMAIL, "receiverrmail@domain", "Test", "This is a test")
email_sent = SendMessage(service, email)
print('Message Id:', email_sent['id'])
except errors.HttpError as err:
print('\n---------------You have the following error-------------')
print(err)
print('---------------You have the following error-------------\n')
if __name__ == '__main__':
main()
通知
您还需要通过在您的 G Suite 帐户上设置 Managing API client access 来允许您的服务帐户访问 Google 的 API。
您不会伤脑筋...只需使用电子邮件和 smtplib 库即可。如果您问我,通过 Python 发送电子邮件非常简单有趣。我在下面给出了我的代码,您应该基于此开发自己的代码。如果有效,请告诉我 - 我会很高兴。在这里....
import email, smtplib, os, time, fnmatch
from datetime import date, timedelta
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
def sendMailTo(recepient_id, today):
login_id = 'myemailID@gmail.com'
login_pwd = "mypassword"
fro_ = login_id
s_name = 'smtp.gmail.com'
s_port = 587
fileList = []
fi_type = '*.pdf'
file_path = "C:\Myfolder\Subfolder"
srvr = smtplib.SMTP(s_name, s_port)
srvr.ehlo()
srvr.starttls()
srvr.ehlo()
srvr.login(login_id, login_pwd)
sub = "Your subject here"
# loading MIMEMultipart obj onto outer var
outer = MIMEMultipart('alternative')
outer["From"] = 'Your company/Personal Name'
outer["To"] = recepient_id
outer['Subject'] = sub
# storing only pdf files
fileList = fnmatch.filter(os.listdir(file_path), fi_type)
for fi in fileList:
fi_name = os.path.join(file_path, fi)
fp = open(fi_name, 'rb')
img = MIMEImage(fp.read(), _subtype='jpg')
fp.close()
img.add_header('Content-disposition', "attachment", filename = fi)
outer.attach(img)
#start sending email with attachment with original file name
srvr.sendmail(fro_, recepient_id, outer.as_string())
part = None
outer = None
srvr.quit()