Julien
11/18/2025, 3:22 PMMarvin
11/18/2025, 3:22 PMMarvin
11/18/2025, 3:28 PMpip install prefect-email
- Create and save SMTP credentials as a block:
from prefect_email import EmailServerCredentials, SMTPType
creds = EmailServerCredentials(
username="smtp-user",
password="your-password", # will be stored as a SecretStr
smtp_server="<http://smtp.yourcompany.com|smtp.yourcompany.com>", # your SMTP host
smtp_type=SMTPType.TLS, # or SMTPType.SSL
smtp_port=587, # match your server
verify=True,
)
creds.save("corp-smtp", overwrite=True)
- Create a tiny flow that sends the email:
from prefect import flow
from prefect_email import email_send_message, EmailServerCredentials
@flow(name="send-email-notification")
def notify(subject: str, body: str, to: list[str], email_from: str | None = None):
creds = EmailServerCredentials.load("corp-smtp")
email_send_message(
subject=subject,
msg=body,
email_server_credentials=creds,
email_from=email_from,
email_to=to,
)
- Deploy this flow (e.g., with prefect deploy from your project).
- Create an Automation:
- Trigger: When a flow run enters state Failed or Crashed
- Action: Run a deployment (select your notify deployment)
- Parameters (use templates so the email contains details about the failing run):
- subject (template): [{{ flow_run.state_type }}] {{ flow_run.name }}
- body (template):
Flow: {{ flow.name }}
Deployment: {{ deployment.name }}
Run: {{ flow_run.name }} ({{ flow_run.id }})
State: {{ flow_run.state_type }} - {{ flow_run.state.message }}
Start: {{ flow_run.start_time }}
Tags: {{ flow_run.tags }}
- to: e.g. ["<mailto:oncall@yourcompany.com|oncall@yourcompany.com>"]
- email_from: e.g. <mailto:alerts@yourcompany.com|alerts@yourcompany.com>
Docs:
- prefect-email integration
- Using templates in Automations
- Automation triggers and events
2) Alternative: Call a webhook action
If you already have an HTTP endpoint that sends email via your SMTP (e.g., an internal service), you can use the “Call a webhook” action in Automations and template the payload with {{ flow_run... }} data. This avoids running a flow but requires an HTTP service you control.
To directly answer your observation: the built-in “Send a notification” action is limited to predefined providers. For custom SMTP, trigger a flow (option 1) or call your own webhook (option 2).
Would you like me to draft the exact Automation parameters or a sample deployment command based on your repo structure and work pool name?Julien
11/18/2025, 4:05 PMJulien
11/18/2025, 4:07 PMMarvin
11/18/2025, 4:07 PMMarvin
11/18/2025, 4:11 PMemail_send_message task inside a flow will schedule and run it; the flow will wait for child tasks to finish before completing.
If the flow run shows “successful” but you didn’t get an email, it’s almost always configuration or environment. Here’s a quick checklist to pinpoint the issue:
- Did the email_send_message task actually run and succeed?
- In the flow run page, look for a green task run named email_send_message. If it’s missing or failed, the logs will explain why.
- Ensure required fields are set explicitly:
- `email_to`: string or list of strings (e.g., "<mailto:oncall@yourcompany.com|oncall@yourcompany.com>" or ["<mailto:oncall@yourcompany.com|oncall@yourcompany.com>"])
- `email_from`: many SMTP servers require a valid sender that’s allowed (often must match the authenticated user/domain)
- Verify SMTP settings match your server:
- STARTTLS: use SMTPType.TLS and port 587
- Implicit TLS: use SMTPType.SSL and port 465
- Example:
from prefect_email import EmailServerCredentials, SMTPType
creds = EmailServerCredentials(
username="smtp-user",
password="your-password",
smtp_server="<http://smtp.yourcompany.com|smtp.yourcompany.com>",
smtp_type=SMTPType.TLS, # or SMTPType.SSL
smtp_port=587,
)
- Corporate/self-signed certs: if you’re on a custom SMTP with a self-signed cert, a quick test is:
creds = EmailServerCredentials(..., verify=False)
If that works, you have a certificate trust issue to fix properly.
- Network egress: make sure your worker environment can reach the SMTP host/port (no firewall/security group blocks).
- Automation parameters: if you’re templating values, confirm they aren’t empty at runtime.
- For example, ensure to resolves to a real address:
- ["<mailto:oncall@yourcompany.com|oncall@yourcompany.com>"]
- And subject/body templates don’t error.
Minimal working example inside a flow (explicit arguments):
from prefect import flow
from prefect_email import email_send_message, EmailServerCredentials, SMTPType
@flow
def test_email():
creds = EmailServerCredentials(
username="smtp-user",
password="your-password",
smtp_server="<http://smtp.yourcompany.com|smtp.yourcompany.com>",
smtp_type=SMTPType.TLS,
smtp_port=587,
)
email_send_message(
subject="Test from Prefect",
msg="This is a test.",
email_server_credentials=creds,
email_from="<mailto:alerts@yourcompany.com|alerts@yourcompany.com>",
email_to=["<mailto:oncall@yourcompany.com|oncall@yourcompany.com>"],
)
if __name__ == "__main__":
test_email()
If this test flow’s email_send_message task shows success but no email arrives:
- Check your SMTP server logs for rejections (e.g., 550/553 sender/recipient issues)
- Try using email_from = the SMTP username or an allowed sender in that domain
If you can share:
- the snippet that calls email_send_message
- your EmailServerCredentials settings (redact secrets)
- the task run logs and the Automation parameters
…I can help spot the exact culprit quickly.
Docs:
- prefect-email integration
- Using templates in Automations