Sending Transactional Email from Python with httpx and Piisend
Learn how to send transactional emails efficiently from your Python applications using the httpx library and Piisend's robust email API. This guide covers basic sends, error handling, idempotency, and leveraging email templates for developers.
Section 1
Getting Started: Sending Your First Email with httpx and Piisend
Sending transactional emails from Python is straightforward with Piisend's REST API and the httpx library. httpx is a modern, async-first HTTP client for Python, offering a familiar API similar to requests but with added async capabilities. To begin, ensure you have httpx installed (pip install httpx) and your Piisend API key ready. This example demonstrates a basic email send.
1import httpx2import os3 4PIISEND_API_KEY = os.getenv("PIISEND_API_KEY")5API_URL = "https://api.piisend.com/api/v1/emails"6 7def send_simple_email():8 headers = {9 "Authorization": f"Bearer {PIISEND_API_KEY}",10 "Content-Type": "application/json"11 }12 payload = {13 "to": ["recipient@example.com"],14 "subject": "Your First Piisend Email",15 "html": "<p>Hello from <strong>Piisend</strong> and <i>httpx</i>!</p>",16 "text": "Hello from Piisend and httpx!"17 }18 19 try:20 response = httpx.post(API_URL, headers=headers, json=payload)21 response.raise_for_status() # Raises HTTPStatusError for bad responses (4xx or 5xx)22 print(f"Email sent successfully: {response.json()}")23 except httpx.HTTPStatusError as e:24 print(f"HTTP error occurred: {e.response.status_code} - {e.response.text}")25 except httpx.RequestError as e:26 print(f"An error occurred while requesting: {e}")27 28if __name__ == "__main__":29 send_simple_email()Section 2
Handling API Responses and Errors Gracefully
Robust applications must handle API responses and potential errors effectively. Piisend's API returns clear JSON responses for both success and failure. When an email is successfully queued, you'll receive a 200 OK status with a message and a unique email_id. In case of errors, such as invalid API keys or malformed requests, Piisend will return an appropriate HTTP status code (e.g., 400 Bad Request, 401 Unauthorized) along with a JSON body detailing the error. Always check the response status and parse the JSON body for detailed feedback.
1{2 "message": "Email queued successfully",3 "email_id": "eml_xxxxxxxxxxxxxxxx"4}Section 3
Ensuring Idempotency for Reliable Email Sends
Idempotency is crucial for transactional systems, preventing duplicate actions if an API request is retried due to network issues or client-side errors. Piisend supports idempotency using the Idempotency-Key header. By providing a unique, client-generated key with each request, you ensure that even if the same request is sent multiple times, the email is only processed and sent once. This is particularly useful for critical emails like order confirmations or password resets.
1import httpx2import os3import uuid4 5PIISEND_API_KEY = os.getenv("PIISEND_API_KEY")6API_URL = "https://api.piisend.com/api/v1/emails"7 8def send_idempotent_email(recipient_email, order_id):9 idempotency_key = f"order-confirmation-{order_id}"10 11 headers = {12 "Authorization": f"Bearer {PIISEND_API_KEY}",13 "Content-Type": "application/json",14 "Idempotency-Key": idempotency_key15 }16 payload = {17 "to": [recipient_email],18 "subject": f"Order {order_id} Confirmation",19 "html": f"<p>Thank you for your order <b>#{order_id}</b>!</p>",20 "text": f"Thank you for your order #{order_id}!"21 }22 23 try:24 response = httpx.post(API_URL, headers=headers, json=payload)25 response.raise_for_status()26 print(f"Idempotent email sent/processed: {response.json()}")27 except httpx.HTTPStatusError as e:28 print(f"HTTP error occurred: {e.response.status_code} - {e.response.text}")29 except httpx.RequestError as e:30 print(f"An error occurred while requesting: {e}")31 32if __name__ == "__main__":33 # Example usage with a unique order ID34 send_idempotent_email("customer@example.com", "ORD-" + str(uuid.uuid4())[:8])Section 4
Leveraging Email Templates with Merge Variables
For consistent branding and dynamic content, Piisend's email templates are invaluable. You can design your email layouts within the Piisend dashboard and then populate them with personalized data using template_vars. This approach separates content from presentation, making your email sending logic cleaner and easier to manage. Simply provide the template_id and a dictionary of template_vars in your API request, and Piisend will handle the merging.
1import httpx2import os3 4PIISEND_API_KEY = os.getenv("PIISEND_API_KEY")5API_URL = "https://api.piisend.com/api/v1/emails"6 7def send_templated_email(recipient_email, user_name, product_name):8 # Replace 'YOUR_TEMPLATE_ID' with an actual template ID from your Piisend account9 template_id = "tpl_xxxxxxxxxxxxxxxx"10 11 headers = {12 "Authorization": f"Bearer {PIISEND_API_KEY}",13 "Content-Type": "application/json"14 }15 payload = {16 "to": [recipient_email],17 "template_id": template_id,18 "template_vars": {19 "user_name": user_name,20 "product_name": product_name,21 "support_email": "support@yourcompany.com"22 }23 }24 25 try:26 response = httpx.post(API_URL, headers=headers, json=payload)27 response.raise_for_status()28 print(f"Templated email queued successfully: {response.json()}")29 except httpx.HTTPStatusError as e:30 print(f"HTTP error occurred: {e.response.status_code} - {e.response.text}")31 except httpx.RequestError as e:32 print(f"An error occurred while requesting: {e}")33 34if __name__ == "__main__":35 send_templated_email("jane.doe@example.com", "Jane Doe", "Premium Widget")