← All ivy-nodes
IVYXSTUDIO · IVY NODE
E
Email Builder
ivy.node.email-builder · v0.2.0
ivyx✓
Builds an email message with a plain-text body and an optional attachment, given as bytes or as a file path, and returns it with its attachment count. The message is a handle for email-provider in the same run.
#Email
Inputs
| Field | Type | Description |
|---|---|---|
| from_emailrequired | string | Sender address. |
| to_emailrequired | string | Recipient address. |
| subjectrequired | string | Subject line. |
| bodyrequired | string | Plain-text body. |
| file_buffer | Not declared | An attachment's bytes; give file_name with it. |
| file_name | string | The attachment's file name; give file_buffer with it, or leave it out with file_path to use the file's own name. |
| file_path | string | An attachment as a file path, relative to the workspace; an alternative to file_buffer. |
Outputs
| Field | Type | Description |
|---|---|---|
| email_messagerequired | Not declared | The message, for email-provider. |
| attachment_countrequired | integer | How many attachments the message carries. |
Source
python
inp = __ivy_ctx__["nodes"][__ivy_node_id__]["input"]
import os
from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
file_buffer = inp.get("file_buffer")
file_path = inp.get("file_path")
file_name = inp.get("file_name")
if file_buffer is not None and file_path:
raise ValueError("Give file_buffer or file_path, not both.")
if (file_buffer is None) != (not file_name) and not file_path:
raise ValueError("file_buffer and file_name must be provided together.")
email_message = MIMEMultipart()
email_message["From"] = inp["from_email"]
email_message["To"] = inp["to_email"]
email_message["Subject"] = inp["subject"]
email_message.attach(MIMEText(inp["body"], "plain"))
data = None
if file_path:
if not os.path.isfile(file_path):
raise FileNotFoundError(f"There is no file at {file_path!r} to attach.")
with open(file_path, "rb") as handle_:
data = handle_.read()
file_name = file_name or os.path.basename(file_path)
elif file_buffer is not None:
file_buffer.seek(0)
data = file_buffer.getvalue()
if data is not None:
attachment = MIMEBase("application", "octet-stream")
attachment.set_payload(data)
encoders.encode_base64(attachment)
attachment.add_header("Content-Disposition", f'attachment; filename="{file_name}"')
email_message.attach(attachment)
out = __ivy_ctx__["nodes"][__ivy_node_id__]["output"]
out["email_message"] = email_message
out["attachment_count"] = max(0, len(email_message.get_payload()) - 1)Tests
Requires: python:3.9
- plain
A message with no attachment carries only its body.
- with-attachment
A buffer and a file name make one attachment.
- with-path
A file path makes one attachment, named after the file.
- missing-path
A path with no file behind it fails the step and names it.
- buffer-without-name
An attachment with no file name is refused.