{"id":44569095,"url":"https://github.com/lettr-com/lettr-python","last_synced_at":"2026-04-18T19:02:18.399Z","repository":{"id":337114008,"uuid":"1152175232","full_name":"lettr-com/lettr-python","owner":"lettr-com","description":"Official Python SDK for the Lettr email API","archived":false,"fork":false,"pushed_at":"2026-04-17T13:28:46.000Z","size":221,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-17T15:34:24.407Z","etag":null,"topics":["api","email","email-api","email-delivery","lettr","pip","python","python-sdk","sdk","transactional-email"],"latest_commit_sha":null,"homepage":"https://lettr.com","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lettr-com.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-07T13:32:23.000Z","updated_at":"2026-04-17T13:26:24.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/lettr-com/lettr-python","commit_stats":null,"previous_names":["lettr-com/lettr-python"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/lettr-com/lettr-python","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lettr-com%2Flettr-python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lettr-com%2Flettr-python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lettr-com%2Flettr-python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lettr-com%2Flettr-python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lettr-com","download_url":"https://codeload.github.com/lettr-com/lettr-python/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lettr-com%2Flettr-python/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31980783,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T17:30:12.329Z","status":"ssl_error","status_checked_at":"2026-04-18T17:29:59.069Z","response_time":103,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","email","email-api","email-delivery","lettr","pip","python","python-sdk","sdk","transactional-email"],"created_at":"2026-02-14T02:00:01.510Z","updated_at":"2026-04-18T19:02:18.391Z","avatar_url":"https://github.com/lettr-com.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Lettr for Python SDK\n\nThe official Python SDK for the [Lettr Email API](https://lettr.com). Send transactional emails with tracking, attachments, templates, and personalization.\n\n## Installation\n\n```bash\npip install lettr\n```\n\n## Quick Start\n\n```python\nimport lettr\n\nclient = lettr.Lettr(\"lttr_your_api_key\")\n\nclient.emails.send(\n    from_email=\"you@example.com\",\n    to=[\"user@example.com\"],\n    subject=\"Hello from Lettr!\",\n    html=\"\u003ch1\u003eWelcome!\u003c/h1\u003e\",\n)\n```\n\n## Usage\n\n### Health \u0026 Authentication\n\n```python\n# Check API health (no authentication required)\nhealth = client.health()\nprint(health.status)  # \"ok\"\n\n# Validate your API key\nauth = client.auth_check()\nprint(f\"Team: {auth.team_name} (ID: {auth.team_id})\")\n```\n\n### Sending Emails\n\n```python\nimport lettr\n\nclient = lettr.Lettr(\"lttr_your_api_key\")\n\n# Simple email\nresponse = client.emails.send(\n    from_email=\"sender@example.com\",\n    to=[\"recipient@example.com\"],\n    subject=\"Hello!\",\n    html=\"\u003ch1\u003eHello\u003c/h1\u003e\u003cp\u003eWelcome to our service!\u003c/p\u003e\",\n    text=\"Hello\\n\\nWelcome to our service!\",\n)\n\nprint(response.request_id)  # \"12345678901234567890\"\nprint(response.accepted)    # 1\n```\n\n#### With Options\n\n```python\nresponse = client.emails.send(\n    from_email=\"sender@example.com\",\n    from_name=\"Acme Inc\",\n    to=[\"recipient@example.com\"],\n    cc=[\"manager@example.com\"],\n    bcc=[\"archive@example.com\"],\n    reply_to=\"support@example.com\",\n    subject=\"Your Order Confirmation\",\n    html=\"\u003ch1\u003eOrder Confirmed\u003c/h1\u003e\",\n    text=\"Order Confirmed\",\n    tag=\"order-confirmation\",\n    headers={\"X-Order-Id\": \"12345\"},\n    options=lettr.EmailOptions(\n        click_tracking=True,\n        open_tracking=True,\n        transactional=True,\n    ),\n    metadata={\"order_id\": \"12345\"},\n)\n```\n\n#### With Attachments\n\n```python\nimport base64\n\nwith open(\"invoice.pdf\", \"rb\") as f:\n    pdf_data = base64.b64encode(f.read()).decode()\n\nresponse = client.emails.send(\n    from_email=\"billing@example.com\",\n    to=[\"customer@example.com\"],\n    subject=\"Your Invoice\",\n    html=\"\u003cp\u003ePlease find your invoice attached.\u003c/p\u003e\",\n    attachments=[\n        lettr.Attachment(\n            name=\"invoice.pdf\",\n            type=\"application/pdf\",\n            data=pdf_data,\n        )\n    ],\n)\n```\n\n#### Using Templates\n\n```python\nresponse = client.emails.send(\n    from_email=\"hello@example.com\",\n    to=[\"user@example.com\"],\n    template_slug=\"welcome-email\",\n    substitution_data={\n        \"first_name\": \"John\",\n        \"company\": \"Acme Inc\",\n    },\n)\n```\n\n### Scheduling Emails\n\n```python\n# Schedule an email for future delivery\nresponse = client.emails.schedule(\n    from_email=\"sender@example.com\",\n    to=[\"recipient@example.com\"],\n    subject=\"Scheduled Message\",\n    html=\"\u003cp\u003eThis was scheduled!\u003c/p\u003e\",\n    scheduled_at=\"2025-12-01T10:00:00Z\",\n)\nprint(f\"Scheduled: {response.request_id}\")\n\n# Get scheduled email details\ndetail = client.emails.get_scheduled(response.request_id)\nprint(f\"{detail.subject} ({detail.state}) -\u003e {detail.recipients}\")\n\n# Cancel a scheduled email\nclient.emails.cancel_scheduled(\"transmission_id\")\n```\n\n### Listing \u0026 Retrieving Emails\n\n```python\n# List sent emails\nemail_list = client.emails.list(per_page=10)\nfor email in email_list.results:\n    print(f\"{email.subject} -\u003e {email.rcpt_to}\")\n\n# Paginate with cursor\nnext_page = client.emails.list(cursor=email_list.next_cursor)\n\n# Filter by recipient\nfiltered = client.emails.list(recipients=\"user@example.com\")\n\n# Filter by date range\nfiltered = client.emails.list(from_date=\"2026-01-01\", to_date=\"2026-01-31\")\n\n# Get email details (all events for a transmission)\ndetail = client.emails.get(\"request_id_here\")\nprint(f\"{detail.subject} -\u003e {detail.recipients} ({detail.state})\")\nfor event in detail.events:\n    print(f\"{event.type}: {event.timestamp}\")\n```\n\n### Email Events\n\n```python\n# List email events with filtering\nevents = client.emails.list_events(\n    events=[\"delivery\", \"bounce\"],\n    recipients=[\"user@example.com\"],\n    from_date=\"2025-01-01\",\n    to_date=\"2025-12-31\",\n    per_page=50,\n)\n\nfor event in events.results:\n    print(f\"{event.type}: {event.rcpt_to} at {event.timestamp}\")\n    if event.geo_ip:\n        print(f\"  Location: {event.geo_ip.city}, {event.geo_ip.country}\")\n    if event.user_agent_parsed:\n        print(f\"  Client: {event.user_agent_parsed.agent_family}\")\n```\n\n### Domains\n\n```python\n# List all domains\ndomains = client.domains.list()\nfor domain in domains:\n    print(f\"{domain.domain} - {domain.status_label}\")\n\n# Add a new sending domain\ndomain = client.domains.create(\"example.com\")\nprint(domain.dkim)  # DKIM config for DNS setup\n\n# Get domain details (includes DMARC, SPF, DNS provider info)\ndomain = client.domains.get(\"example.com\")\nprint(f\"DMARC: {domain.dmarc_status}, SPF: {domain.spf_status}\")\n\n# Verify DNS records\nverification = client.domains.verify(\"example.com\")\nprint(f\"DKIM: {verification.dkim_status}\")\nprint(f\"CNAME: {verification.cname_status}\")\nprint(f\"DMARC: {verification.dmarc_status}\")\nprint(f\"SPF: {verification.spf_status}\")\n\n# Delete a domain\nclient.domains.delete(\"example.com\")\n```\n\n### Templates\n\n```python\n# List templates\ntemplate_list = client.templates.list(per_page=10)\nfor template in template_list.templates:\n    print(f\"{template.name} ({template.slug})\")\n\n# Create a template\ntemplate = client.templates.create(\n    name=\"Welcome Email\",\n    html=\"\u003ch1\u003eHello {{NAME}}!\u003c/h1\u003e\u003cp\u003eWelcome aboard.\u003c/p\u003e\",\n)\n\n# Get a template\ntemplate = client.templates.get(\"welcome-email\")\nprint(template.html)\n\n# Get template HTML\nhtml = client.templates.get_html(project_id=1, slug=\"welcome-email\")\n\n# Update a template (creates a new version)\ntemplate = client.templates.update(\n    \"welcome-email\",\n    html=\"\u003ch1\u003eHi {{NAME}}!\u003c/h1\u003e\u003cp\u003eUpdated content.\u003c/p\u003e\",\n)\n\n# Get merge tags\nmerge_tags = client.templates.get_merge_tags(\"welcome-email\")\nfor tag in merge_tags.merge_tags:\n    print(f\"{tag.key} (required: {tag.required})\")\n\n# Delete a template\nclient.templates.delete(\"welcome-email\")\n```\n\n### Webhooks\n\n```python\n# List webhooks\nwebhooks = client.webhooks.list()\nfor webhook in webhooks:\n    print(f\"{webhook.name}: {webhook.url} (enabled: {webhook.enabled})\")\n\n# Create a webhook\nwebhook = client.webhooks.create(\n    name=\"My Webhook\",\n    url=\"https://example.com/webhook\",\n    auth_type=\"none\",\n    events_mode=\"selected\",\n    events=[\"delivery\", \"bounce\", \"spam_complaint\"],\n)\n\n# Create with authentication\nwebhook = client.webhooks.create(\n    name=\"Secure Webhook\",\n    url=\"https://example.com/webhook\",\n    auth_type=\"basic\",\n    events_mode=\"all\",\n    auth_username=\"user\",\n    auth_password=\"secret\",\n)\n\n# Update a webhook\nwebhook = client.webhooks.update(\n    \"webhook-abc123\",\n    name=\"Renamed Webhook\",\n    active=False,\n)\n\n# Get webhook details\nwebhook = client.webhooks.get(\"webhook-abc123\")\n\n# Delete a webhook\nclient.webhooks.delete(\"webhook-abc123\")\n```\n\n### Projects\n\n```python\n# List projects\nproject_list = client.projects.list()\nfor project in project_list.projects:\n    print(f\"{project.emoji} {project.name}\")\n```\n\n## Error Handling\n\nThe SDK raises typed exceptions for all API errors:\n\n```python\nimport lettr\n\nclient = lettr.Lettr(\"lttr_your_api_key\")\n\ntry:\n    client.emails.send(\n        from_email=\"sender@example.com\",\n        to=[\"recipient@example.com\"],\n        subject=\"Hello\",\n        html=\"\u003cp\u003eHello!\u003c/p\u003e\",\n    )\nexcept lettr.ValidationError as e:\n    print(f\"Validation failed: {e.message}\")\n    print(f\"Field errors: {e.errors}\")\nexcept lettr.AuthenticationError:\n    print(\"Invalid API key\")\nexcept lettr.ForbiddenError:\n    print(\"Access forbidden\")\nexcept lettr.NotFoundError as e:\n    print(f\"Not found: {e.message}\")\nexcept lettr.RateLimitError as e:\n    print(f\"Rate limited: {e.message} (code: {e.error_code})\")\nexcept lettr.BadRequestError as e:\n    print(f\"Bad request: {e.message} (code: {e.error_code})\")\nexcept lettr.ServerError as e:\n    print(f\"Server error: {e.message}\")\nexcept lettr.LettrError as e:\n    print(f\"Unexpected error: {e.message}\")\n```\n\n### Exception Hierarchy\n\n| Exception | HTTP Status | Description |\n|---|---|---|\n| `LettrError` | -- | Base exception for all errors |\n| `AuthenticationError` | 401 | Missing or invalid API key |\n| `ForbiddenError` | 403 | Access forbidden |\n| `ValidationError` | 422 | Request validation failed |\n| `NotFoundError` | 404 | Resource not found |\n| `ConflictError` | 409 | Resource already exists |\n| `BadRequestError` | 400 | Invalid domain or request |\n| `RateLimitError` | 429 | Quota or rate limit exceeded |\n| `ServerError` | 500, 502 | Server-side error |\n\n## Context Manager\n\nUse the client as a context manager to automatically close connections:\n\n```python\nwith lettr.Lettr(\"lttr_your_api_key\") as client:\n    client.emails.send(\n        from_email=\"sender@example.com\",\n        to=[\"recipient@example.com\"],\n        subject=\"Hello!\",\n        html=\"\u003cp\u003eHello!\u003c/p\u003e\",\n    )\n# Connection pool is automatically closed\n```\n\n## Requirements\n\n- Python 3.8+\n- [httpx](https://www.python-httpx.org/) (installed automatically)\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flettr-com%2Flettr-python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flettr-com%2Flettr-python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flettr-com%2Flettr-python/lists"}