Bryan
06/26/2026, 4:08 PMMarvin
06/26/2026, 4:08 PMMarvin
06/26/2026, 4:09 PMEmailServerCredentials block with your own SMTP server.
Install the integration first:
bash
pip install "prefect[email]"
prefect block register -m prefect_email
Example flow:
python
from prefect import flow
from prefect_email import EmailServerCredentials, SMTPType, email_send_message
@flow
async def send_test_email():
creds = EmailServerCredentials(
username="<mailto:alerts@mycompany.com|alerts@mycompany.com>",
password="super-secret-password",
smtp_server="<http://smtp.mycompany.com|smtp.mycompany.com>",
smtp_type=SMTPType.STARTTLS, # or "STARTTLS"
smtp_port=587, # optional if using the standard port
verify=True, # set False only if you must skip cert verification
)
# Optional: save for reuse in later flows
creds.save("my-smtp-creds", overwrite=True)
await email_send_message(
subject="Prefect test email",
msg="<h1>Hello from Prefect</h1><p>This was sent through my SMTP server.</p>",
msg_plain="Hello from Prefect. This was sent through my SMTP server.",
email_server_credentials=creds,
email_from="<mailto:alerts@mycompany.com|alerts@mycompany.com>",
email_to=["<mailto:you@example.com|you@example.com>"],
)
if __name__ == "__main__":
send_test_email()
If you want to reuse a saved block later:
python
from prefect import flow
from prefect_email import EmailServerCredentials, email_send_message
@flow
async def send_reused_email():
creds = EmailServerCredentials.load("my-smtp-creds")
await email_send_message(
subject="Another email",
msg="Sent using a saved EmailServerCredentials block.",
email_server_credentials=creds,
email_from="<mailto:alerts@mycompany.com|alerts@mycompany.com>",
email_to="<mailto:you@example.com|you@example.com>",
)
A few notes:
- smtp_server can be any hostname, like <http://smtp.mycompany.com|smtp.mycompany.com>
- smtp_type should usually be:
- SMTPType.SSL for port 465
- SMTPType.STARTTLS for port 587
- SMTPType.INSECURE for port 25
- email_send_message is async, so using async def on the flow is the cleanest approach
- If your SMTP server uses a self-signed cert, you may need verify=False
Relevant API signatures:
- EmailServerCredentials(username=None, password=..., smtp_server=..., smtp_type=..., smtp_port=None, verify=True)
- email_send_message(subject, msg, email_server_credentials, msg_plain=None, email_from=None, email_to=None, email_to_cc=None, email_to_bcc=None, attachments=None, inline_images=None)
Docs / package links:
- prefect-email integration docs
- Prefect docs
If you want, I can also give you:
1. a sync version of this example, or
2. an example that sends email on flow failure.Bryan
06/26/2026, 5:46 PMMarvin
06/26/2026, 5:46 PMMarvin
06/26/2026, 5:46 PMmsg can be HTML.
Use:
- msg for the HTML body
- msg_plain for the plain-text fallback
Example:
python
await email_send_message(
subject="Test HTML email",
msg="""
<html>
<body>
<h1>Hello</h1>
<p>This is an <b>HTML</b> email from Prefect.</p>
</body>
</html>
""",
msg_plain="Hello - this is an HTML email from Prefect.",
email_server_credentials=creds,
email_from="<mailto:alerts@mycompany.com|alerts@mycompany.com>",
email_to="<mailto:you@example.com|you@example.com>",
)
If you omit msg_plain, the email can still be sent, but including it is a good practice for clients that prefer plain text.
Docs:
- prefect-email integration docsBryan
06/26/2026, 7:15 PMMarvin
06/26/2026, 7:15 PMMarvin
06/26/2026, 7:16 PMpython
import smtplib
from prefect import flow
from prefect_email import EmailServerCredentials, email_send_message
@flow
async def send_email():
creds = EmailServerCredentials.load("my-smtp-creds")
try:
message = await email_send_message(
subject="Test email",
msg="<h1>Hello</h1>",
msg_plain="Hello",
email_server_credentials=creds,
email_from="<mailto:alerts@mycompany.com|alerts@mycompany.com>",
email_to="<mailto:you@example.com|you@example.com>",
)
print("Email sent successfully")
print(f"Subject: {message['Subject']}")
except smtplib.SMTPAuthenticationError as exc:
print(f"Authentication failed: {exc}")
except smtplib.SMTPRecipientsRefused as exc:
print(f"Recipient rejected: {exc}")
except smtplib.SMTPException as exc:
print(f"SMTP error: {exc}")
except Exception as exc:
print(f"Other error: {exc}")
2. Check the return value
On success, email_send_message(...) returns the email message object (MIMEMultipart), so getting that object back is another sign it worked.
3. In Prefect state terms
email_send_message is a Prefect task:
- success => task goes to Completed
- failure => task goes to Failed
So in the Prefect UI, you can also inspect the task run state.
Important caveat
“Sent successfully” here means the SMTP server accepted the message. It does not guarantee final delivery to the inbox — the email could still later bounce, get filtered, or be rejected downstream.
Common failure types
- SMTPAuthenticationError → bad username/password
- SMTPRecipientsRefused → invalid or rejected recipient
- SMTPConnectError / SMTPServerDisconnected → connection issues
- ValueError → missing recipients
- FileNotFoundError → bad attachment path
If you want, I can also show you a version that logs success/failure into the Prefect run logs so it’s easy to see in the UI.Bring your towel and join one of the fastest growing data communities. Welcome to our second-generation open source orchestration platform, a completely rethought approach to dataflow automation.
Powered by