{"id":72,"library":"sendgrid","title":"SendGrid","description":"Official Python SDK for the Twilio SendGrid Email API v3. Owned by Twilio. Two send patterns exist: Mail helper class and raw dict. v6.x is a breaking change from v5.x. Free plan retired May 2025. SDK last meaningfully updated Sep 2025 — in maintenance mode.","status":"maintenance","version":"6.12.5","language":"python","source_language":"en","source_url":"https://github.com/sendgrid/sendgrid-python","tags":["email","sendgrid","twilio","transactional-email","python","api"],"install":[{"cmd":"pip install sendgrid","lang":"bash","label":"Python"}],"dependencies":[{"reason":"SendGrid's own HTTP client library. Installed automatically.","package":"python-http-client","optional":false},{"reason":"Required for webhook signature validation.","package":"starkbank-ecdsa","optional":false}],"imports":[{"note":"sg.send(message) is the v6 shorthand. sg.client.mail.send.post(request_body=message.get()) is the older explicit pattern — both work in v6 but sg.send() is simpler.","wrong":"sg = sendgrid.SendGridAPIClient(api_key='...')\nresponse = sg.client.mail.send.post(request_body=message.get())","symbol":"SendGridAPIClient (Mail helper)","correct":"from sendgrid import SendGridAPIClient\nfrom sendgrid.helpers.mail import Mail\n\nmessage = Mail(\n    from_email='from@example.com',\n    to_emails='to@example.com',\n    subject='Subject',\n    html_content='<strong>Hello</strong>'\n)\nsg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))\nresponse = sg.send(message)"}],"quickstart":{"code":"import os\nfrom sendgrid import SendGridAPIClient\nfrom sendgrid.helpers.mail import Mail\n\nmessage = Mail(\n    from_email='sender@example.com',\n    to_emails='recipient@example.com',\n    subject='Sending with SendGrid',\n    html_content='<strong>Hello from Python!</strong>'\n)\n\ntry:\n    sg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))\n    response = sg.send(message)\n    print(response.status_code)  # 202 = accepted\nexcept Exception as e:\n    print(str(e))","lang":"python","description":"202 Accepted means queued for delivery, not delivered. The from_email must be a verified sender or from a verified domain."},"warnings":[{"fix":"Upgrade to v6 and use Mail helper class with sg.send(message) or pass raw dict to sg.client.mail.send.post(request_body=data).","message":"v6.x is a breaking change from v5.x. The SendGridAPIClient constructor signature changed, and the send pattern via sg.client.mail.send.post() requires a raw dict, not the old Mail object's .get() call in some patterns.","severity":"breaking","affected_versions":"< 6.0.0"},{"fix":"Check response.status_code == 202 for success. Use Event Webhooks for delivery/bounce/open tracking.","message":"202 Accepted does not mean delivered. SendGrid queues emails and delivers asynchronously. Checking response.status_code == 200 will always fail — the success code is 202.","severity":"gotcha","affected_versions":"all"},{"fix":"Complete Domain Authentication in SendGrid dashboard, or verify the specific sender address via Single Sender Verification.","message":"The from_email must be a verified sender (Single Sender Verification) or from a domain with Domain Authentication set up. Sending from unverified addresses returns 403 Forbidden.","severity":"gotcha","affected_versions":"all"},{"fix":"For free email sending, consider Resend (100/day free) or Postmark (100/month free). For existing SendGrid integrations, upgrade to a paid plan.","message":"SendGrid Free plan was retired May 27, 2025. New accounts can no longer use the free tier after this date. Existing free accounts had 60 days before billing required.","severity":"gotcha","affected_versions":"all"},{"fix":"For new SendGrid features, use the low-level client: sg.client._(endpoint).method(request_body=data).","message":"SDK GitHub repository last updated September 2025. The library is in maintenance mode — new SendGrid features may not be reflected in the SDK. Use sg.client._('endpoint').post(request_body=data) for endpoints not in the helper.","severity":"gotcha","affected_versions":"all"},{"fix":"It is recommended to use a virtual environment for pip operations to avoid permission issues. Additionally, pip can be updated by running `pip install --upgrade pip`.","message":"The test environment generated pip warnings about running as the 'root' user and an available update.","severity":"gotcha","affected_versions":"all"}],"env_vars":{"optional":[{"name":"SENDGRID_WEBHOOK_PUBLIC_KEY","note":"ECDSA public key for Event Webhook signature verification."}],"required":[{"name":"SENDGRID_API_KEY","note":"API key from SendGrid Settings > API Keys. Needs 'Mail Send' permission at minimum."}]},"last_verified":"2026-05-12T06:52:26.801Z","next_check":"2026-06-01T00:00:00.000Z","problems":[],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":80,"quickstart_tag":"verified","pypi_latest":null,"install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.17,"mem_mb":6.9,"disk_size":"36.4M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.12,"mem_mb":6.9,"disk_size":"37M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.28,"mem_mb":7.7,"disk_size":"38.9M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.23,"mem_mb":7.7,"disk_size":"39M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.23,"mem_mb":7.6,"disk_size":"30.6M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.23,"mem_mb":7.6,"disk_size":"31M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.2,"mem_mb":7.5,"disk_size":"30.2M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.23,"mem_mb":7.5,"disk_size":"31M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.17,"mem_mb":6.8,"disk_size":"36.7M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.16,"mem_mb":6.8,"disk_size":"37M"}]},"quickstart_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"quickstart runs on critical runtimes, recently tested","results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":0},{"runtime":"python:3.12-slim","exit_code":0},{"runtime":"python:3.13-alpine","exit_code":0},{"runtime":"python:3.13-slim","exit_code":0},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]}}