连接到Gmail使用电子邮件地址和密码与Python

huangapple go评论135阅读模式
英文:

Connect to Gmail Using Email Address and Password with Python

问题

I am trying to connect to my Gmail account using Python. I want to connect to it using both SMTP and IMAP. I am aware that it is possible to use an app password to make this connection, but is there a way to use the actual email password instead?

我正在尝试使用Python连接到我的Gmail帐户。我希望能够同时使用SMTP和IMAP进行连接。我知道可以使用应用程序密码来建立连接,但是否有一种方法可以使用实际的电子邮件密码呢?

I have been reading this particular article,
我一直在阅读这篇特定的文章,

连接到Gmail使用电子邮件地址和密码与Python

Do I have that right?
我理解得对吗?

Given below is the code I am using to send and search emails. Like I said though, this only works with an app password,

以下是我用来发送和搜索电子邮件的代码。不过,就像我之前说的,这仅适用于应用程序密码,

  1. import smtplib
  2. import imaplib
  3. import email
  4. from email.mime.multipart import MIMEMultipart
  5. from email.mime.text import MIMEText
  6. import pandas as pd
  7. class EmailClient:
  8. def __init__(self, email, password, smtp_server='smtp.gmail.com', smtp_port=587, imap_server="imap.gmail.com"):
  9. self.email = email
  10. self.password = password
  11. self.smtp_server = smtplib.SMTP(smtp_server, smtp_port)
  12. self.imap_server = imaplib.IMAP4_SSL(imap_server)
  13. def send_email(self, to_addr, subject, body):
  14. msg = MIMEMultipart()
  15. msg['From'] = self.email
  16. msg['To'] = to_addr
  17. msg['Subject'] = subject
  18. msg.attach(MIMEText(body, 'plain'))
  19. self.smtp_server.starttls()
  20. self.smtp_server.login(self.email, self.password)
  21. self.smtp_server.send_message(msg)
  22. self.smtp_server.quit()
  23. def search_email(self, mailbox="INBOX", subject=None, to=None, from_=None, since_date=None, until_date=None,
  24. since_emailid=None):
  25. self.imap_server.login(self.email, self.password)
  26. self.imap_server.select(mailbox)
  27. query_parts = []
  28. if subject is not None:
  29. query_parts.append(f'(SUBJECT "{subject}")')
  30. if to is not None:
  31. query_parts.append(f'(TO "{to}")')
  32. if from_ is not None:
  33. query_parts.append(f'(FROM "{from_}")')
  34. if since_date is not None:
  35. since_date_str = since_date.strftime("%d-%b-%Y")
  36. query_parts.append(f'(SINCE "{since_date_str}")')
  37. if until_date is not None:
  38. until_date_str = until_date.strftime("%d-%b-%Y")
  39. query_parts.append(f'(BEFORE "{until_date_str}")')
  40. if since_emailid is not None:
  41. query_parts.append(f'(UID {since_emailid}:*)')
  42. query = ' '.join(query_parts)
  43. ret = []
  44. resp, items = self.imap_server.uid('search', None, query)
  45. items = items[0].split()
  46. for emailid in items[::-1]:
  47. resp, data = self.imap_server.uid('fetch', emailid, "(BODY[HEADER.FIELDS (SUBJECT TO FROM DATE)])")
  48. try:
  49. raw_email = data[0][1].decode("utf-8")
  50. except UnicodeDecodeError:
  51. ValueError(f"Could not decode email with id {emailid}")
  52. email_message = email.message_from_string(raw_email)
  53. email_line = {}
  54. email_line['id'] = emailid
  55. email_line["to"] = email_message['To']
  56. email_line["from"] = email_message['From']
  57. email_line["subject"] = str(email_message['Subject'])
  58. email_line["created_at"] = email_message['Date']
  59. resp, email_data = self.imap_server.uid('fetch', emailid, '(BODY[TEXT])')
  60. email_line["body"] = email_data[0][1].decode('utf-8')
  61. ret.append(email_line)
  62. self.imap_server.logout()
  63. return pd.DataFrame(ret)
英文:

I am trying to connect to my Gmail account using Python. I want to connect to it using both SMTP and IMAP. I am aware that it is possible to use an app password to make this connection, but is there a way to use the actual email password instead?

I have been reading this particular article,
<br>
https://support.google.com/accounts/answer/6010255#zippy=%2Cif-less-secure-app-access-is-on-for-your-account%2Cif-less-secure-app-access-is-off-for-your-account

The warning given at the top tells me that it is not possible to do so, even if 'Less secure app access' is allowed,

连接到Gmail使用电子邮件地址和密码与Python

Do I have that right?

Given below is the code I am using to send and search emails. Like I said though, this only works with an app password,

  1. import smtplib
  2. import imaplib
  3. import email
  4. from email.mime.multipart import MIMEMultipart
  5. from email.mime.text import MIMEText
  6. import pandas as pd
  7. class EmailClient:
  8. def __init__(self, email, password, smtp_server=&#39;smtp.gmail.com&#39;, smtp_port=587, imap_server=&quot;imap.gmail.com&quot;):
  9. self.email = email
  10. self.password = password
  11. self.smtp_server = smtplib.SMTP(smtp_server, smtp_port)
  12. self.imap_server = imaplib.IMAP4_SSL(imap_server)
  13. def send_email(self, to_addr, subject, body):
  14. msg = MIMEMultipart()
  15. msg[&#39;From&#39;] = self.email
  16. msg[&#39;To&#39;] = to_addr
  17. msg[&#39;Subject&#39;] = subject
  18. msg.attach(MIMEText(body, &#39;plain&#39;))
  19. self.smtp_server.starttls()
  20. self.smtp_server.login(self.email, self.password)
  21. self.smtp_server.send_message(msg)
  22. self.smtp_server.quit()
  23. def search_email(self, mailbox=&quot;INBOX&quot;, subject=None, to=None, from_=None, since_date=None, until_date=None,
  24. since_emailid=None):
  25. self.imap_server.login(self.email, self.password)
  26. self.imap_server.select(mailbox)
  27. query_parts = []
  28. if subject is not None:
  29. query_parts.append(f&#39;(SUBJECT &quot;{subject}&quot;)&#39;)
  30. if to is not None:
  31. query_parts.append(f&#39;(TO &quot;{to}&quot;)&#39;)
  32. if from_ is not None:
  33. query_parts.append(f&#39;(FROM &quot;{from_}&quot;)&#39;)
  34. if since_date is not None:
  35. since_date_str = since_date.strftime(&quot;%d-%b-%Y&quot;)
  36. query_parts.append(f&#39;(SINCE &quot;{since_date_str}&quot;)&#39;)
  37. if until_date is not None:
  38. until_date_str = until_date.strftime(&quot;%d-%b-%Y&quot;)
  39. query_parts.append(f&#39;(BEFORE &quot;{until_date_str}&quot;)&#39;)
  40. if since_emailid is not None:
  41. query_parts.append(f&#39;(UID {since_emailid}:*)&#39;)
  42. query = &#39; &#39;.join(query_parts)
  43. ret = []
  44. resp, items = self.imap_server.uid(&#39;search&#39;, None, query)
  45. items = items[0].split()
  46. for emailid in items[::-1]:
  47. resp, data = self.imap_server.uid(&#39;fetch&#39;, emailid, &quot;(BODY[HEADER.FIELDS (SUBJECT TO FROM DATE)])&quot;)
  48. try:
  49. raw_email = data[0][1].decode(&quot;utf-8&quot;)
  50. except UnicodeDecodeError:
  51. ValueError(f&quot;Could not decode email with id {emailid}&quot;)
  52. email_message = email.message_from_string(raw_email)
  53. email_line = {}
  54. email_line[&#39;id&#39;] = emailid
  55. email_line[&quot;to&quot;] = email_message[&#39;To&#39;]
  56. email_line[&quot;from&quot;] = email_message[&#39;From&#39;]
  57. email_line[&quot;subject&quot;] = str(email_message[&#39;Subject&#39;])
  58. email_line[&quot;created_at&quot;] = email_message[&#39;Date&#39;]
  59. resp, email_data = self.imap_server.uid(&#39;fetch&#39;, emailid, &#39;(BODY[TEXT])&#39;)
  60. email_line[&quot;body&quot;] = email_data[0][1].decode(&#39;utf-8&#39;)
  61. ret.append(email_line)
  62. self.imap_server.logout()
  63. return pd.DataFrame(ret)

答案1

得分: 1

"我知道可以使用应用程序密码进行连接,但是否可以使用实际的电子邮件密码呢?

不,不能这样做,您需要执行以下两种操作之一。

  1. 在帐户上启用两步验证并创建应用程序密码。
  2. 使用Xoauth2并请求用户授权以访问其帐户。

您的代码在我看来很好,只需创建一个应用程序密码。

Xoauth示例

  1. from __future__ import print_function
  2. import base64
  3. import os.path
  4. import smtplib
  5. from email.mime.text import MIMEText
  6. from google.auth.transport.requests import Request
  7. from google.oauth2.credentials import Credentials
  8. from google_auth_oauthlib.flow import InstalledAppFlow
  9. # 如果修改了这些范围,请删除token.json文件。
  10. SCOPES = ['https://mail.google.com/']
  11. # 用户令牌存储
  12. USER_TOKENS = 'token.json'
  13. # 应用程序凭据
  14. CREDENTIALS = 'C:\YouTube\dev\credentials.json'
  15. def getToken() -> str:
  16. creds = None
  17. # 文件token.json存储用户的访问和刷新令牌,并在首次授权流程完成时自动生成。
  18. if os.path.exists(USER_TOKENS):
  19. creds = Credentials.from_authorized_user_file(USER_TOKENS, SCOPES)
  20. creds.refresh(Request())
  21. # 如果没有(有效的)凭据可用,让用户登录。
  22. if not creds or not creds.valid:
  23. if creds and creds.expired and creds.refresh_token:
  24. creds.refresh(Request())
  25. else:
  26. flow = InstalledAppFlow.from_client_secrets_file(CREDENTIALS, SCOPES)
  27. creds = flow.run_local_server(port=0)
  28. # 保存凭据以供下次运行
  29. with open(USER_TOKENS, 'w') as token:
  30. token.write(creds.to_json())
  31. return creds.token
  32. def generate_oauth2_string(username, access_token) -> str:
  33. auth_string = 'user=' + username + '\1auth=Bearer ' + access_token + '\1\1'
  34. return base64.b64encode(auth_string.encode('ascii')).decode('ascii')
  35. def send_email(host, port, subject, msg, sender, recipients):
  36. access_token = getToken()
  37. auth_string = generate_oauth2_string(sender, access_token)
  38. msg = MIMEText(msg)
  39. msg['Subject'] = subject
  40. msg['From'] = sender
  41. msg['To'] = ', '.join(recipients)
  42. server = smtplib.SMTP(host, port)
  43. server.starttls()
  44. server.docmd('AUTH', 'XOAUTH2 ' + auth_string)
  45. server.sendmail(sender, recipients, msg.as_string())
  46. server.quit()
  47. def main():
  48. host = "smtp.gmail.com"
  49. port = 587
  50. user = "REDACTED@gmail.com"
  51. recipient = "REDACTED@gmail.com"
  52. subject = "Test email Oauth2"
  53. msg = "Hello world"
  54. sender = user
  55. recipients = [recipient]
  56. send_email(host, port, subject, msg, sender, recipients)
  57. if __name__ == '__main__':
  58. main()

"

英文:

>I am aware that it is possible to use an app password to make this connection, but is there a way to use the actual email password instead?

No there is not, you need to do one of two things.

  1. enable 2fa on the account and create an apps password
  2. Use Xoauth2 and request authorization of the user to access their account.

Your code looks fine to me just crate an apps password.

Xoauth sample

  1. from __future__ import print_function
  2. import base64
  3. import os.path
  4. import smtplib
  5. from email.mime.text import MIMEText
  6. from google.auth.transport.requests import Request
  7. from google.oauth2.credentials import Credentials
  8. from google_auth_oauthlib.flow import InstalledAppFlow
  9. # If modifying these scopes, delete the file token.json.
  10. SCOPES = [&#39;https://mail.google.com/&#39;]
  11. # user token storage
  12. USER_TOKENS = &#39;token.json&#39;
  13. # application credentials
  14. CREDENTIALS = &#39;C:\YouTube\dev\credentials.json&#39;
  15. def getToken() -&gt; str:
  16. creds = None
  17. # The file token.json stores the user&#39;s access and refresh tokens, and is
  18. # created automatically when the authorization flow completes for the first
  19. # time.
  20. if os.path.exists(USER_TOKENS):
  21. creds = Credentials.from_authorized_user_file(USER_TOKENS, SCOPES)
  22. creds.refresh(Request())
  23. # If there are no (valid) credentials available, let the user log in.
  24. if not creds or not creds.valid:
  25. if creds and creds.expired and creds.refresh_token:
  26. creds.refresh(Request())
  27. else:
  28. flow = InstalledAppFlow.from_client_secrets_file(CREDENTIALS, SCOPES)
  29. creds = flow.run_local_server(port=0)
  30. # Save the credentials for the next run
  31. with open(USER_TOKENS, &#39;w&#39;) as token:
  32. token.write(creds.to_json())
  33. return creds.token
  34. def generate_oauth2_string(username, access_token) -&gt; str:
  35. auth_string = &#39;user=&#39; + username + &#39;\1auth=Bearer &#39; + access_token + &#39;\1\1&#39;
  36. return base64.b64encode(auth_string.encode(&#39;ascii&#39;)).decode(&#39;ascii&#39;)
  37. def send_email(host, port, subject, msg, sender, recipients):
  38. access_token = getToken()
  39. auth_string = generate_oauth2_string(sender, access_token)
  40. msg = MIMEText(msg)
  41. msg[&#39;Subject&#39;] = subject
  42. msg[&#39;From&#39;] = sender
  43. msg[&#39;To&#39;] = &#39;, &#39;.join(recipients)
  44. server = smtplib.SMTP(host, port)
  45. server.starttls()
  46. server.docmd(&#39;AUTH&#39;, &#39;XOAUTH2 &#39; + auth_string)
  47. server.sendmail(sender, recipients, msg.as_string())
  48. server.quit()
  49. def main():
  50. host = &quot;smtp.gmail.com&quot;
  51. port = 587
  52. user = &quot;REDACTED@gmail.com&quot;
  53. recipient = &quot;REDACTED@gmail.com&quot;
  54. subject = &quot;Test email Oauth2&quot;
  55. msg = &quot;Hello world&quot;
  56. sender = user
  57. recipients = [recipient]
  58. send_email(host, port, subject, msg, sender, recipients)
  59. if __name__ == &#39;__main__&#39;:
  60. main()

huangapple
  • 本文由 发表于 2023年8月10日 12:56:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/76872744.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定