{"id":36686922,"url":"https://github.com/sklarsa/django-sendgrid-v5","last_synced_at":"2026-01-12T11:15:29.200Z","repository":{"id":44658492,"uuid":"97976038","full_name":"sklarsa/django-sendgrid-v5","owner":"sklarsa","description":"An implementation of Django's EmailBackend compatible with sendgrid-python v5+","archived":false,"fork":false,"pushed_at":"2025-07-01T12:22:48.000Z","size":260,"stargazers_count":342,"open_issues_count":2,"forks_count":57,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-10-05T20:13:26.911Z","etag":null,"topics":["django","django-emailtools","sendgrid","sendgrid-api"],"latest_commit_sha":null,"homepage":"","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/sklarsa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","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}},"created_at":"2017-07-21T18:26:02.000Z","updated_at":"2025-09-01T06:44:16.000Z","dependencies_parsed_at":"2022-07-13T21:44:47.894Z","dependency_job_id":"ddc3d050-bfab-483d-8600-1265325ad27d","html_url":"https://github.com/sklarsa/django-sendgrid-v5","commit_stats":{"total_commits":205,"total_committers":25,"mean_commits":8.2,"dds":0.5951219512195122,"last_synced_commit":"09ec1fd94f6aaaca25d6aaede7cf5aa9bc6e26a6"},"previous_names":["sklarsa/django-sendgrid-v4"],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/sklarsa/django-sendgrid-v5","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sklarsa%2Fdjango-sendgrid-v5","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sklarsa%2Fdjango-sendgrid-v5/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sklarsa%2Fdjango-sendgrid-v5/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sklarsa%2Fdjango-sendgrid-v5/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sklarsa","download_url":"https://codeload.github.com/sklarsa/django-sendgrid-v5/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sklarsa%2Fdjango-sendgrid-v5/sbom","scorecard":{"id":829798,"data":{"date":"2025-08-11","repo":{"name":"github.com/sklarsa/django-sendgrid-v5","commit":"fd862bbe5b705bf948f617d5d33e12288f37bf4b"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4,"checks":[{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/pipeline.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":3,"reason":"Found 10/30 approved changesets -- score normalized to 3","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"1 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pipeline.yml:11: update your workflow using https://app.stepsecurity.io/secureworkflow/sklarsa/django-sendgrid-v5/pipeline.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pipeline.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/sklarsa/django-sendgrid-v5/pipeline.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pipeline.yml:35: update your workflow using https://app.stepsecurity.io/secureworkflow/sklarsa/django-sendgrid-v5/pipeline.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pipeline.yml:37: update your workflow using https://app.stepsecurity.io/secureworkflow/sklarsa/django-sendgrid-v5/pipeline.yml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/pipeline.yml:17","Warn: pipCommand not pinned by hash: .github/workflows/pipeline.yml:18","Warn: pipCommand not pinned by hash: .github/workflows/pipeline.yml:42","Warn: pipCommand not pinned by hash: .github/workflows/pipeline.yml:43","Info:   0 out of   4 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   4 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":9,"reason":"1 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2024-48 / GHSA-fj7x-q9j7-g6q6"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 17 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-23T17:27:16.618Z","repository_id":44658492,"created_at":"2025-08-23T17:27:16.619Z","updated_at":"2025-08-23T17:27:16.619Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28197365,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2026-01-04T02:00:06.065Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["django","django-emailtools","sendgrid","sendgrid-api"],"created_at":"2026-01-12T11:15:29.124Z","updated_at":"2026-01-12T11:15:29.189Z","avatar_url":"https://github.com/sklarsa.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# django-sendgrid-v5\n\n[![Latest Release](https://img.shields.io/pypi/v/django-sendgrid-v5.svg)](https://pypi.python.org/pypi/django-sendgrid-v5/)\n\nThis package implements an email backend for Django that relies on sendgrid's REST API for message delivery.\n\nIt is under active development, and pull requests are more than welcome\\!\n\nTo use the backend, simply install the package (using pip), set the `EMAIL_BACKEND` setting in Django, and add a `SENDGRID_API_KEY` key (set to the appropriate value) to your Django settings.\n\n## How to Install\n\n1. `pip install django-sendgrid-v5`\n2. In your project's settings.py script:\n    1. Set `EMAIL_BACKEND = \"sendgrid_backend.SendgridBackend\"`\n    2. Set the SENDGRID\\_API\\_KEY in settings.py to your api key that was provided to you by sendgrid. `SENDGRID_API_KEY = os.environ[\"SENDGRID_API_KEY\"]`\n\n### Other settings\n\n1. To toggle sandbox mode (when django is running in DEBUG mode), set `SENDGRID_SANDBOX_MODE_IN_DEBUG = True/False`.\n    1. To err on the side of caution, this defaults to True, so emails sent in DEBUG mode will not be delivered, unless this setting is explicitly set to False.\n1. To enable sandbox mode unconditionally (regardless of DEBUG), set `SENDGRID_SANDBOX_MODE = True`. This is useful for non-production environments like QA or staging where DEBUG may be False but you still don't want to send real emails.\n1. `SENDGRID_ECHO_TO_STDOUT` will echo to stdout or any other file-like\n    object that is passed to the backend via the `stream` kwarg.\n1. `SENDGRID_TRACK_EMAIL_OPENS` - defaults to true and tracks email open events via the Sendgrid service. These events are logged in the Statistics UI, Email Activity interface, and are reported by the Event Webhook.\n1. `SENDGRID_TRACK_CLICKS_HTML` - defaults to true and, if enabled in your Sendgrid account, will tracks click events on links found in the HTML message sent.\n1. `SENDGRID_TRACK_CLICKS_PLAIN` - defaults to true and, if enabled in your Sendgrid account, will tracks click events on links found in the plain text message sent.\n1. `SENDGRID_HOST_URL` - Allows changing the base API URI. Set to `https://api.eu.sendgrid.com` to use the EU region.\n\n## Usage\n\n### Simple\n\n```python\nfrom django.core.mail import send_mail\n\nsend_mail(\n    'Subject here',\n    'Here is the message.',\n    'from@example.com',\n    ['to@example.com'],\n    fail_silently=False,\n)\n```\n\n### Dynamic Template with JSON Data\n\nFirst, create a [dynamic template](https://mc.sendgrid.com/dynamic-templates) and copy the ID.\n\n```python\nfrom django.core.mail import EmailMessage\n\nmsg = EmailMessage(\n  from_email='to@example.com',\n  to=['to@example.com'],\n)\nmsg.template_id = \"your-dynamic-template-id\"\nmsg.dynamic_template_data = {\n  \"title\": foo\n}\nmsg.send(fail_silently=False)\n```\n\n### The kitchen sink EmailMessage (all of the supported sendgrid-specific properties)\n\n```python\nfrom django.core.mail import EmailMessage\n\nmsg = EmailMessage(\n  from_email='to@example.com',\n  to=['to@example.com'],\n  cc=['cc@example.com'],\n  bcc=['bcc@example.com'],\n)\n\n# Personalization custom args\n# https://sendgrid.com/docs/for-developers/sending-email/personalizations/\nmsg.custom_args = {'arg1': 'value1', 'arg2': 'value2'}\n\n# Reply to email address (sendgrid only supports 1 reply-to email address)\nmsg.reply_to = 'reply-to@example.com'\n\n# Send at (accepts an integer per the sendgrid docs)\n# https://docs.sendgrid.com/for-developers/sending-email/scheduling-parameters#send-at\nmsg.send_at = 1600188812\n\n# Transactional templates\n# https://sendgrid.com/docs/ui/sending-email/how-to-send-an-email-with-dynamic-transactional-templates/\nmsg.template_id = \"your-dynamic-template-id\"\nmsg.dynamic_template_data = {  # Sendgrid v6+ only\n  \"title\": foo\n}\nmsg.substitutions = {\n  \"title\": bar\n}\n\n# Unsubscribe groups\n# https://sendgrid.com/docs/ui/sending-email/unsubscribe-groups/\nmsg.asm = {'group_id': 123, 'groups_to_display': ['group1', 'group2']}\n\n# Categories\n# https://sendgrid.com/docs/glossary/categories/\nmsg.categories = ['category1', 'category2']\n\n# IP Pools\n# https://sendgrid.com/docs/ui/account-and-settings/ip-pools/\nmsg.ip_pool_name = 'my-ip-pool'\n\n\nmsg.send(fail_silently=False)\n```\n\n### Webhook Helpers\n\nVersion 6 of the `sendgrid` package or later includes some helper functions to\ncryptographically verify the signature and contents of events from the Sendgrid\nEvents webhook.\n\nThis project includes some additional helpers for Sendgrid's webhook signature\nverification.\n\n1. Enable signature verification for Sendgrid webhooks (see [Sendgrid docs](https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/getting-started-event-webhook-security-features#enable-signature-verification)). Once you have saved the webhook and edited it again, copy the verification key.\n2. Modify your project's `settings.py` and set `SENDGRID_WEBHOOK_VERIFICATION_KEY` to your verification key value.\n3. Setup a project URLConf and view. Below is an example view you can adapt to your needs.\n\n```python\nimport json\nfrom datetime import datetime\n\nfrom django.db import transaction\nfrom django.http import HttpRequest, HttpResponse\nfrom django.views.decorators.csrf import csrf_exempt\nfrom django.views.decorators.http import require_POST\nfrom post_office.models import Email, Log as EmailLog, STATUS\nfrom pytz import utc\nfrom sendgrid_backend.decorators import verify_sendgrid_webhook_signature\n\nEVENTS = {'delivered': STATUS.sent, 'bounce': STATUS.failed, 'blocked': STATUS.failed}\n\n@csrf_exempt\n@require_POST\n@verify_sendgrid_webhook_signature\ndef sendgrid_deliverability_webhook_handler(request: HttpRequest) -\u003e HttpResponse:\n    \"\"\"\n    Example webhook handler to save delivered, bounce, and blocked events to\n    the email log.\n    \"\"\"\n    for msg_dict in reversed(json.loads(request.body)):\n        if event := EVENTS.get(msg_dict.get('event', None), None):\n            event_timestamp = datetime.fromtimestamp(msg_dict.get('timestamp'), tz=utc)\n            with transaction.atomic():\n                Email.objects.filter(message_id=msg_dict.get('smtp-id', None)).update(\n                    last_updated=event_timestamp,\n                    status=event,\n                )\n\n                EmailLog.objects.create(\n                    email__message_id=msg_dict.get('smtp-id', None),\n                    date=event_timestamp,\n                    status=event,\n                    message=json.dumps(msg_dict),\n                )\n    return HttpResponse(\"ok\")\n```\n\n\n### FAQ\n**How to change a Sender's Name ?**\n\n\n`from_email=\"John Smith \u003cjohn.smith@example.org\u003e\"`\nYou can just include the name in the from_email field of the _```EmailMessage```_ class \n\n```\nmsg = EmailMessage(\n  from_email='Sender Name \u003cfrom@example.com\u003e',\n  to=['to@example.com'],\n)\n```\n\n**How to make mails to multiple users private (hide all the email addresses to which the mail is sent) to each person (personalization) ?**\n\n\nSetting the `make_private` attribute to `True` will help us achieve it\n```\nmsg = EmailMessage(\n  from_email='Sender Name \u003cfrom@example.com\u003e',\n  to=['to@example.com','abc@example.com','xyz@example.com'],\n)\nmsg.make_private = True\n```\n\n## Examples\n\n- Marcelo Canina [(@marcanuy)](https://github.com/marcanuy) wrote a great article demonstrating how to integrate `django-sendgrid-v5` into your Django application on his site: [https://simpleit.rocks/python/django/adding-email-to-django-the-easiest-way/](https://simpleit.rocks/python/django/adding-email-to-django-the-easiest-way/)\n- RX-36 [(@DevWoody856)](https://github.com/DevWoody856) demonstrates how to use `django-sendgrid-v5` to make a contact form for your web application: https://rx-36.life/create-a-contact-form-using-sendgrid-with-django/\n\n\n## Stargazers over time\n\n[![Stargazers over time](https://starchart.cc/sklarsa/django-sendgrid-v5.svg)](https://starchart.cc/sklarsa/django-sendgrid-v5)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsklarsa%2Fdjango-sendgrid-v5","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsklarsa%2Fdjango-sendgrid-v5","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsklarsa%2Fdjango-sendgrid-v5/lists"}