{"id":37077784,"url":"https://github.com/ruedigervoigt/bote","last_synced_at":"2026-01-14T09:01:34.801Z","repository":{"id":62560345,"uuid":"273872612","full_name":"RuedigerVoigt/bote","owner":"RuedigerVoigt","description":"A Python library to send email. Enforces encryption if not sending via localhost.","archived":false,"fork":false,"pushed_at":"2025-11-09T10:02:17.000Z","size":82,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-01-04T00:46:53.021Z","etag":null,"topics":["email","email-sender","python-email","python-library","security","smtp","ssl","tls"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RuedigerVoigt.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2020-06-21T09:26:21.000Z","updated_at":"2025-11-09T01:12:43.000Z","dependencies_parsed_at":"2022-11-03T14:30:34.674Z","dependency_job_id":null,"html_url":"https://github.com/RuedigerVoigt/bote","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/RuedigerVoigt/bote","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RuedigerVoigt%2Fbote","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RuedigerVoigt%2Fbote/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RuedigerVoigt%2Fbote/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RuedigerVoigt%2Fbote/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RuedigerVoigt","download_url":"https://codeload.github.com/RuedigerVoigt/bote/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RuedigerVoigt%2Fbote/sbom","scorecard":{"id":123023,"data":{"date":"2025-08-11","repo":{"name":"github.com/RuedigerVoigt/bote","commit":"abc1d6177800eb3f6d1c6fe3b55c976c6f10b222"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.1,"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":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","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":"0 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":"SAST","score":10,"reason":"SAST tool detected: CodeQL","details":["Info: SAST configuration detected: CodeQL","Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"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":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/codeql-analysis.yml:1","Warn: no topLevel permission defined: .github/workflows/macos-test.yml:1","Warn: no topLevel permission defined: .github/workflows/mypy.yml:1","Warn: no topLevel permission defined: .github/workflows/pytest.yml:1","Warn: no topLevel permission defined: .github/workflows/windows-test.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":"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/codeql-analysis.yml:28: update your workflow using https://app.stepsecurity.io/secureworkflow/RuedigerVoigt/bote/codeql-analysis.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:41: update your workflow using https://app.stepsecurity.io/secureworkflow/RuedigerVoigt/bote/codeql-analysis.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:52: update your workflow using https://app.stepsecurity.io/secureworkflow/RuedigerVoigt/bote/codeql-analysis.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:66: update your workflow using https://app.stepsecurity.io/secureworkflow/RuedigerVoigt/bote/codeql-analysis.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/macos-test.yml:25: update your workflow using https://app.stepsecurity.io/secureworkflow/RuedigerVoigt/bote/macos-test.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/macos-test.yml:28: update your workflow using https://app.stepsecurity.io/secureworkflow/RuedigerVoigt/bote/macos-test.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/mypy.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/RuedigerVoigt/bote/mypy.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/mypy.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/RuedigerVoigt/bote/mypy.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pytest.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/RuedigerVoigt/bote/pytest.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pytest.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/RuedigerVoigt/bote/pytest.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/windows-test.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/RuedigerVoigt/bote/windows-test.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/windows-test.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/RuedigerVoigt/bote/windows-test.yml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/macos-test.yml:34","Warn: pipCommand not pinned by hash: .github/workflows/macos-test.yml:35","Warn: pipCommand not pinned by hash: .github/workflows/macos-test.yml:39","Warn: pipCommand not pinned by hash: .github/workflows/mypy.yml:27","Warn: pipCommand not pinned by hash: .github/workflows/mypy.yml:28","Warn: pipCommand not pinned by hash: .github/workflows/mypy.yml:29","Warn: pipCommand not pinned by hash: .github/workflows/pytest.yml:26","Warn: pipCommand not pinned by hash: .github/workflows/pytest.yml:27","Warn: pipCommand not pinned by hash: .github/workflows/pytest.yml:31","Warn: pipCommand not pinned by hash: .github/workflows/pytest.yml:32","Warn: pipCommand not pinned by hash: .github/workflows/pytest.yml:33","Info:   0 out of  12 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of  11 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":"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":"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":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: 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":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"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"}}]},"last_synced_at":"2025-08-16T02:57:08.877Z","repository_id":62560345,"created_at":"2025-08-16T02:57:08.877Z","updated_at":"2025-08-16T02:57:08.877Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28414732,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T08:38:59.149Z","status":"ssl_error","status_checked_at":"2026-01-14T08:38:43.588Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: 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":["email","email-sender","python-email","python-library","security","smtp","ssl","tls"],"created_at":"2026-01-14T09:01:33.820Z","updated_at":"2026-01-14T09:01:34.793Z","avatar_url":"https://github.com/RuedigerVoigt.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Bote\n\n![Supported Python Versions](https://img.shields.io/pypi/pyversions/bote)\n![Last commit](https://img.shields.io/github/last-commit/RuedigerVoigt/bote)\n![pypi version](https://img.shields.io/pypi/v/bote)\n[![Downloads](https://pepy.tech/badge/bote)](https://pepy.tech/project/bote)\n[![Coverage](https://img.shields.io/badge/coverage-97%25-brightgreen)](https://www.ruediger-voigt.eu/coverage/bote/index.html)\n\n\"Bote\" is German for messenger or courier. The `bote` library sends plain-text email from localhost or a remote SMTP server. The base functionality is in the standard library, but this package improves upon that in several ways:\n* Enforce that any connection to a SMTP server - except `localhost` / `127.0.0.1` / `::1` - is encrypted. (Of course this does not influence how the SMTP server sends the message to the recipient.)\n* Good error messages\n* Type-Hints in the code ([PEP 484](https://www.python.org/dev/peps/pep-0484/))\n* Extensive testing\n* Automatically wrap messages preserving intentional line-breaks.\n\n## How to use it\n\n\n```python\nimport os\nimport bote\n\nmail_settings = {\n    'server': 'smtp.example.com',\n    'server_port': 587,\n    'encryption': 'starttls',  # or 'ssl', or 'off'\n    # Best practice: get secrets from environment variables\n    # instead of hardcoded strings =\u003e\n    'username': os.environ.get('MAIL_USER'),\n    'passphrase': os.environ.get('MAIL_PASSPHRASE'),\n    'recipient': 'foo@example.com',\n    'sender': 'bar@example.com',\n    'wrap_width': 80}\n\nmailer = bote.Mailer(mail_settings)\n\nmailer.send_mail('Test bote',  # subject\n                 'It worked!'  # mail body\n                 )\n\n# If the setting recipient is a dictionary and contains\n# an admin key:\nmailer.send_mail_to_admin('Test', 'Message for the admin')\n```\n\nAll parameters except `recipient` and `sender` are optional as `bote` has defaults for all others:\n\nParameter | Default Value\n--- | ---\n`server`| `localhost`\n`server_port`| `None`\n`encryption`| `off`\n`username`| `None`\n`passphrase`| `None`\n`wrap_width`| `80`\n\nThe parameter `recipient` can either be an email address as a string or a dictionary. In the later case, this should have a `default` key with the standard recipient as value. Otherwise the recipient has to be set for every message. If it contains an `admin` key, the shorthand command `send_mail_to_admin` can be used.\n\n### Keeping Your Credentials Save\n\n\u003eYou should not store secrets in code that may be shared or saved to source control.\n\nTo avoid accidental exposure of secrets it is best practice to use environment variables that can be accessed with `os.environ.get()`. The [`python-dotenv`](https://github.com/theskumar/python-dotenv) could be useful for this too - do not forget to add `.env` files to `.gitignore`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fruedigervoigt%2Fbote","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fruedigervoigt%2Fbote","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fruedigervoigt%2Fbote/lists"}