how to send an email with python

How to Send Email with Python in 5 Minutes

Last Updated on August 2, 2026 by ian

Sending transactional email from Python is something every developer needs to do — welcome emails, password resets, order confirmations, OTP codes. This guide shows you exactly how to do it using the ConvertNow Email API and Python’s built-in requests library.

No extra packages. No complex setup. A working email in under 5 minutes.

What you need

• Python 3.8 or above

• A free ConvertNow account — convertnow.co

• 5 minutes

Step 1: Get your API key

Sign up at convertnow.co, go to Email API in the left sidebar, click + New Key, give it a name, and copy the key. It looks like this:

cn_live_gb8Hdp7uXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Store it as an environment variable — never hardcode it:

export CONVERTNOW_API_KEY=cn_live_YOUR_KEY

Step 2: Send your first email

Python’s requests library handles the HTTP call. No SDK installation required.

import os
import requests
response = requests.post(

'https://api.convertnow.co/v1/email/send',

headers={

'Authorization': f'Bearer {os.environ["CONVERTNOW_API_KEY"]}',

'Content-Type': 'application/json',

},

json={

'to': '[email protected]',

'from': '[email protected]',

'subject': 'Hello from Python',

'html': '<h1>It works!</h1><p>Your first email from Python.</p>',

'text': 'It works! Your first email from Python.',

}

)

print(response.json())

# {'id': 'msg_abc123', 'status': 'sent', 'message': 'Email queued for delivery'}

Step 3: Build a reusable send function

For production use, wrap the call in a function with proper error handling:

import os
import requests

API_KEY = os.environ['CONVERTNOW_API_KEY']
BASE_URL = 'https://api.convertnow.co/v1/email/send'

def send_email(to, subject, html=None, text=None,
              from_=None, cc=None, bcc=None,
              reply_to=None, attachments=None, tags=None):
    """
    Send a transactional email via ConvertNow.
    :param to: str or list of str
    :param subject: str
    :param html: str (HTML body)
    :param text: str (plain text fallback)
    :param from_: str (optional, defaults to account sender)
    :param tags: list of str (max 10, for analytics)
    """
    payload = {'to': to, 'subject': subject}
    if html:        payload['html']        = html
    if text:        payload['text']        = text
    if from_:       payload['from']        = from_
    if cc:          payload['cc']          = cc
    if bcc:         payload['bcc']         = bcc
    if reply_to:    payload['reply_to']    = reply_to
    if attachments: payload['attachments'] = attachments
    if tags:        payload['tags']        = tags

    response = requests.post(
        BASE_URL,
        headers={'Authorization': f'Bearer {API_KEY}'},
        json=payload
    )
    response.raise_for_status()
    return response.json()

Step 4: Common transactional email patterns

Welcome email

send_email(
    to=user_email,
    subject=f'Welcome to MyApp, {user_name}!',
    html=f'<h1>Hi {user_name}!</h1><p>Your account is ready.',
    tags=['welcome', 'onboarding']
)

Password reset

send_email(
    to=user_email,
    subject='Reset your password',
    html=f'<p>Click <a href="{reset_url}">here</a> to reset your password. Link expires in 1 hour.</p>',
    tags=['password-reset']
)

Send to multiple recipients

send_email(

to=['[email protected]', '[email protected]'],

subject='Team update',

html='<p>Here is this week's update.</p>'

)

Send with an attachment

import base64

with open('invoice.pdf', 'rb') as f:
    encoded = base64.b64encode(f.read()).decode()

send_email(
    to='[email protected]',
    subject='Your invoice',
    html='<p>Please find your invoice attached.</p>',
    attachments=[{
        'filename': 'invoice.pdf',
        'content': encoded,
        'content_type': 'application/pdf',
    }]
)

Step 5: Send via SMTP with smtplib

If you prefer SMTP over the HTTP API, ConvertNow works as a drop-in SMTP relay on port 465 with implicit SSL:

import smtplib
import ssl
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import os

SMTP_HOST = 'out.convertnow.co'
SMTP_PORT = 465
USERNAME   = '[email protected]'
PASSWORD   = os.environ['CONVERTNOW_API_KEY']

msg = MIMEMultipart('alternative')
msg['Subject'] = 'Hello via SMTP'
msg['From']    = USERNAME
msg['To']      = '[email protected]'
msg.attach(MIMEText('It works!', 'plain'))
msg.attach(MIMEText('<h1>It works!</h1>', 'html'))

context = ssl.create_default_context()
with smtplib.SMTP_SSL(SMTP_HOST, SMTP_PORT, context=context) as server:
    server.login(USERNAME, PASSWORD)
    server.send_message(msg)
    print('Sent via SMTP')

Django: send email in 3 lines

If you’re using Django, configure ConvertNow as your email backend in settings.py and use Django’s built-in send_mail:

# settings.py
EMAIL_BACKEND       = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST          = 'out.convertnow.co'
EMAIL_PORT          = 465
EMAIL_USE_SSL       = True
EMAIL_HOST_USER     = '[email protected]'
EMAIL_HOST_PASSWORD = os.environ['CONVERTNOW_API_KEY']
DEFAULT_FROM_EMAIL  = '[email protected]'
# views.py or anywhere in your app
from django.core.mail import send_mail

send_mail(
    subject='Welcome to MyApp',
    message='Thanks for signing up.',
    from_email='[email protected]',
    recipient_list=['[email protected]'],
    html_message='<h1>Welcome!</h1><p>Thanks for signing up.</p>',
)

Flask: send email from a route

For Flask applications, use the HTTP API directly from your route handler:

import os
import requests
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/signup', methods=['POST'])
def signup():
    data = request.json
    email = data['email']
    name  = data['name']

    # Create user in your database here...

    # Send welcome email
    requests.post(
        'https://api.convertnow.co/v1/email/send',
        headers={'Authorization': f'Bearer {os.environ["CONVERTNOW_API_KEY"]}'},
        json={
            'to': email,
            'subject': f'Welcome, {name}!',
            'html': f'<h1>Hi {name}!</h1><p>Your account is ready.</p>',
            'tags': ['welcome']
        }
    )

    return jsonify({'success': True})

Error handling

Always handle the case where email delivery fails:

try:
    result = send_email(
        to=user_email,
        subject='Welcome',
        html='<p>Welcome!</p>'
    )
    print('Sent:', result['id'])
except requests.exceptions.HTTPError as e:
    error = e.response.json().get('error', 'Unknown error')
    print('Email failed:', error)
    # Log to your monitoring system
except requests.exceptions.ConnectionError:
    print('Could not reach the email API — check your network')

Why ConvertNow instead of Amazon SES or SendGrid?

• No AWS account, no IAM setup, no sandbox approval process

• $99/year flat for 1 million emails/month – SES costs $1,200/year for the same volume

• Bounce handling, suppression management, and analytics included — no CloudWatch required

• Email marketing campaigns on the same account at no extra cost

Start sending for free — convertnow.co — no credit card required

Next steps

• Authenticate your sending domain (DKIM, SPF, DMARC) for better deliverability

• Set up webhooks to receive delivery and failure events in real time

• Manage your suppression list for GDPR-compliant unsubscribe handling