Using the concrete I/O implementations
In addition to the sans-io protocol implementation, this library also provides both an
asynchronous and a synchronous SMTP client class (AsyncSMTPClient
and
SyncSMTPClient
, respectively).
Most SMTP servers, however, require some form of authentication. While it would be unfeasible to provide solutions for every possible situation, the examples below should cover some very common cases and should give you a general idea of how to work with SMTP authentication.
For the OAuth2 examples (further below), you need to install a couple dependencies:
Sending mail via a local SMTP server
from email.message import EmailMessage
import anyio
from smtpproto.auth import PlainAuthenticator
from smtpproto.client import AsyncSMTPClient
async def main() -> None:
client = AsyncSMTPClient(host="localhost", port=25, authenticator=authenticator)
await client.send_message(message)
# If your SMTP server requires basic authentication, this is where you enter that
# info
authenticator = PlainAuthenticator(username="myuser", password="mypassword")
# The message you want to send
message = EmailMessage()
message["From"] = "my.name@mydomain.com"
message["To"] = "somebody@somewhere"
message["Subject"] = "Test from smtpproto"
message.set_content("This is a test.")
# Actually sends the message by running main()
anyio.run(main)
Sending mail via Gmail
The developer documentation for the G Suite describes how to use the XOAUTH2
mechanism for authenticating against the Gmail SMTP server. The following is a practical
example of how to extend the OAuth2Authenticator
class to obtain an
access token and use it to send an email via Gmail.
The following example assumes the presence of an existing G Suite service account
authorized to send email via SMTP (using the https://mail.google.com/
scope).
from datetime import datetime, timedelta
from email.message import EmailMessage
from typing import cast
import anyio
import httpx
import jwt
from smtpproto.auth import JSONWebToken, OAuth2Authenticator
from smtpproto.client import AsyncSMTPClient
class GMailAuthenticator(OAuth2Authenticator):
def __init__(self, username: str, client_id: str, private_key: str):
super().__init__(username)
self.client_id = client_id
self.private_key = private_key
async def get_token(self) -> JSONWebToken:
webtoken = jwt.encode(
{
"iss": self.client_id,
"scope": "https://mail.google.com/",
"aud": "https://oauth2.googleapis.com/token",
"exp": datetime.utcnow() + timedelta(minutes=1),
"iat": datetime.utcnow(),
"sub": self.username,
},
self.private_key,
algorithm="RS256",
)
async with httpx.AsyncClient() as http:
response = await http.post(
"https://oauth2.googleapis.com/token",
data={
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
"assertion": webtoken.decode("ascii"),
},
)
response.raise_for_status()
return cast(JSONWebToken, await response.json())
async def main() -> None:
client = AsyncSMTPClient(host="smtp.gmail.com", authenticator=authenticator)
await client.send_message(message)
authenticator = GMailAuthenticator(
# Your gmail user name
username="my.name@gmail.com",
# Service account ID and private key – these have to be obtained from Gmail
client_id="yourserviceaccount@yourdomain.iam.gserviceaccount.com",
private_key="-----BEGIN PRIVATE KEY-----\n...-----END PRIVATE KEY-----\n",
)
# The message you want to send
message = EmailMessage()
message["From"] = "my.name@gmail.com"
message["To"] = "somebody@somewhere"
message["Subject"] = "Test from smtpproto"
message.set_content("This is a test.")
# Actually sends the message by running main()
anyio.run(main)