<@ULVA73B9P> Give me an example of sending an emai...
# ask-marvin
b
@Marvin Give me an example of sending an email using my own smtp server and the prefect Email Server Credentials block
m
thought for 53.3 seconds
Yep — here’s a simple Prefect 3.x example using the
EmailServerCredentials
block with your own SMTP server. Install the integration first:
Copy code
bash
pip install "prefect[email]"
prefect block register -m prefect_email
Example flow:
Copy code
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:
Copy code
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.
b
@Marvin will this accept an HTML body for the email?
m
thought for 7.9 seconds
Yes —
msg
can be HTML. Use: -
msg
for the HTML body -
msg_plain
for the plain-text fallback Example:
Copy code
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 docs
b
@Marvin how can I tell if the email sent successfully or not?
m
thought for 83.7 seconds
Yes — the main signal is: if it doesn’t raise an exception, it sent successfully. A few concrete ways to tell: 1. Catch exceptions
Copy code
python
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.