<div align="center">
# SahajMails
**Send personalized bulk emails — Free, Secure, Simple**
No servers. No coding. Just upload, type, send.
[](https://badge.fury.io/py/sahajmails)
[](https://python.org)
[](LICENSE)
</div>
---
## Features
- **100% Local**: Your data never leaves your device
- **Gmail App Password**: Secure authentication (no real password used)
- **CSV/Excel Upload**: Supports `.csv`, `.xlsx`, `.xls`
- **Smart Placeholders**: `{{ firstName }}` — case and space tolerant
- **Live Preview**: Real-time HTML rendering
- **Test Email**: Send to yourself before bulk
- **Attachments**: PDFs, images, documents
- **Progress Tracking**: Real-time log and progress bar
- **Markdown & HTML**: Full email formatting support
- **Gmail-Safe**: 2-second delay between sends
---
## Quick Start
```bash
pip install sahajmails
sahajmails
```
Open [http://localhost:8501](http://localhost:8501)
---
## 7-Step Guide
1. **Upload** your contact list (must have `email` column)
2. **Enter** your Gmail and **App Password**
3. **Compose** email using `{{ columnName }}` placeholders
4. **Click** placeholder buttons to copy instantly
5. **Attach** files (optional)
6. **Preview** → **Send Test Email**
7. **Start Bulk Send** → Watch progress
**Example CSV:**
```csv
email,firstName,company
alice@example.com,Alice,Acme Corp
bob@work.com,Bob,StartupXYZ
```
---
## Gmail App Password (Required)
1. Go to [myaccount.google.com/security](https://myaccount.google.com/security)
2. Enable **2-Step Verification**
3. Search **"App Passwords"**
4. Select **App name** → **Generate**
5. Copy the **16-character password** → paste in the app
---
## Installation
```bash
pip install sahajmails
```
Or from source:
```bash
git clone https://github.com/sahajrajmalla/sahajmails.git
cd sahajmails
pip install -e .
```
---
## Development
```bash
# Install dev dependencies
pip install -e .[dev]
# Run tests
pytest tests/
# Build package
python -m build
```
---
## Contributing
Contributions are welcome!
1. Fork the repo
2. Create a branch: `git checkout -b feature/your-idea`
3. Commit changes: `git commit -m "feat: add X"`
4. Push and open a Pull Request
Please follow PEP 8 and include tests.
---
## Security & Privacy
- Runs **entirely on your machine**
- **No data is stored or transmitted**
- **Open source** under MIT License
- Uses **Gmail App Passwords** only
---
## License
[MIT License](LICENSE) – Free for personal and commercial use.
---
<div align="center">
Made with ❤️ by [Sahaj Raj Malla](https://github.com/sahajrajmalla)
</div>
Raw data
{
"_id": null,
"home_page": null,
"name": "sahajmails",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "email, bulk-email, streamlit, gmail, marketing, personalization, csv",
"author": null,
"author_email": "Sahaj Raj Malla <mallasahajraj@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/f7/2b/d4136b2cd0b94072334898e4f16f2e23f449c1aa3d8c161d697448870bfe/sahajmails-1.0.1.tar.gz",
"platform": null,
"description": "<div align=\"center\">\n\n# SahajMails\n\n**Send personalized bulk emails \u2014 Free, Secure, Simple**\n\nNo servers. No coding. Just upload, type, send.\n\n[](https://badge.fury.io/py/sahajmails)\n[](https://python.org)\n[](LICENSE)\n\n</div>\n\n---\n\n## Features\n\n- **100% Local**: Your data never leaves your device \n- **Gmail App Password**: Secure authentication (no real password used) \n- **CSV/Excel Upload**: Supports `.csv`, `.xlsx`, `.xls` \n- **Smart Placeholders**: `{{ firstName }}` \u2014 case and space tolerant \n- **Live Preview**: Real-time HTML rendering \n- **Test Email**: Send to yourself before bulk \n- **Attachments**: PDFs, images, documents \n- **Progress Tracking**: Real-time log and progress bar \n- **Markdown & HTML**: Full email formatting support \n- **Gmail-Safe**: 2-second delay between sends \n\n---\n\n## Quick Start\n\n```bash\npip install sahajmails\nsahajmails\n```\n\nOpen [http://localhost:8501](http://localhost:8501)\n\n---\n\n## 7-Step Guide\n\n1. **Upload** your contact list (must have `email` column) \n2. **Enter** your Gmail and **App Password** \n3. **Compose** email using `{{ columnName }}` placeholders \n4. **Click** placeholder buttons to copy instantly \n5. **Attach** files (optional) \n6. **Preview** \u2192 **Send Test Email** \n7. **Start Bulk Send** \u2192 Watch progress\n\n**Example CSV:**\n```csv\nemail,firstName,company\nalice@example.com,Alice,Acme Corp\nbob@work.com,Bob,StartupXYZ\n```\n\n---\n\n## Gmail App Password (Required)\n\n1. Go to [myaccount.google.com/security](https://myaccount.google.com/security) \n2. Enable **2-Step Verification** \n3. Search **\"App Passwords\"** \n4. Select **App name** \u2192 **Generate** \n5. Copy the **16-character password** \u2192 paste in the app\n\n\n---\n\n## Installation\n\n```bash\npip install sahajmails\n```\n\nOr from source:\n\n```bash\ngit clone https://github.com/sahajrajmalla/sahajmails.git\ncd sahajmails\npip install -e .\n```\n\n---\n\n## Development\n\n```bash\n# Install dev dependencies\npip install -e .[dev]\n\n# Run tests\npytest tests/\n\n# Build package\npython -m build\n```\n\n---\n\n## Contributing\n\nContributions are welcome! \n\n1. Fork the repo \n2. Create a branch: `git checkout -b feature/your-idea` \n3. Commit changes: `git commit -m \"feat: add X\"` \n4. Push and open a Pull Request \n\nPlease follow PEP 8 and include tests.\n\n---\n\n## Security & Privacy\n\n- Runs **entirely on your machine** \n- **No data is stored or transmitted** \n- **Open source** under MIT License \n- Uses **Gmail App Passwords** only \n\n---\n\n## License\n\n[MIT License](LICENSE) \u2013 Free for personal and commercial use.\n\n---\n\n<div align=\"center\">\n\nMade with \u2764\ufe0f by [Sahaj Raj Malla](https://github.com/sahajrajmalla) \n\n\n</div>\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Simple, secure bulk email sender using Gmail + Streamlit",
"version": "1.0.1",
"project_urls": {
"Documentation": "https://github.com/sahajrajmalla/sahajmails/blob/main/docs/USER_GUIDE.md",
"Homepage": "https://github.com/sahajrajmalla/sahajmails",
"Issues": "https://github.com/sahajrajmalla/sahajmails/issues",
"Repository": "https://github.com/sahajrajmalla/sahajmails"
},
"split_keywords": [
"email",
" bulk-email",
" streamlit",
" gmail",
" marketing",
" personalization",
" csv"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "7366ceb90508578151da4105d6a6b039ce4235eb713b63851e7d5419801ba8b2",
"md5": "66167241a1190518cd38f2276d5a3945",
"sha256": "c3729e622ca1ad8900ff251b1d70d72df17f7d92bfc8a89e3aad29bb5527e363"
},
"downloads": -1,
"filename": "sahajmails-1.0.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "66167241a1190518cd38f2276d5a3945",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 11255,
"upload_time": "2025-11-13T12:29:31",
"upload_time_iso_8601": "2025-11-13T12:29:31.040857Z",
"url": "https://files.pythonhosted.org/packages/73/66/ceb90508578151da4105d6a6b039ce4235eb713b63851e7d5419801ba8b2/sahajmails-1.0.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "f72bd4136b2cd0b94072334898e4f16f2e23f449c1aa3d8c161d697448870bfe",
"md5": "f86deecfb3d361d07ee541c86582b2b4",
"sha256": "76fea8741c882f4890e11a6106a2ddddfb7c3f162d6db79100b2c8ef928fbf1c"
},
"downloads": -1,
"filename": "sahajmails-1.0.1.tar.gz",
"has_sig": false,
"md5_digest": "f86deecfb3d361d07ee541c86582b2b4",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 11922,
"upload_time": "2025-11-13T12:29:32",
"upload_time_iso_8601": "2025-11-13T12:29:32.604336Z",
"url": "https://files.pythonhosted.org/packages/f7/2b/d4136b2cd0b94072334898e4f16f2e23f449c1aa3d8c161d697448870bfe/sahajmails-1.0.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-11-13 12:29:32",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "sahajrajmalla",
"github_project": "sahajmails",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [
{
"name": "altair",
"specs": [
[
"==",
"5.5.0"
]
]
},
{
"name": "attrs",
"specs": [
[
"==",
"25.4.0"
]
]
},
{
"name": "black",
"specs": [
[
"==",
"25.11.0"
]
]
},
{
"name": "blinker",
"specs": [
[
"==",
"1.9.0"
]
]
},
{
"name": "build",
"specs": [
[
"==",
"1.3.0"
]
]
},
{
"name": "cachetools",
"specs": [
[
"==",
"6.2.1"
]
]
},
{
"name": "certifi",
"specs": [
[
"==",
"2025.11.12"
]
]
},
{
"name": "charset-normalizer",
"specs": [
[
"==",
"3.4.4"
]
]
},
{
"name": "click",
"specs": [
[
"==",
"8.3.0"
]
]
},
{
"name": "docutils",
"specs": [
[
"==",
"0.22.3"
]
]
},
{
"name": "flake8",
"specs": [
[
"==",
"7.3.0"
]
]
},
{
"name": "gitdb",
"specs": [
[
"==",
"4.0.12"
]
]
},
{
"name": "GitPython",
"specs": [
[
"==",
"3.1.45"
]
]
},
{
"name": "id",
"specs": [
[
"==",
"1.5.0"
]
]
},
{
"name": "idna",
"specs": [
[
"==",
"3.11"
]
]
},
{
"name": "iniconfig",
"specs": [
[
"==",
"2.3.0"
]
]
},
{
"name": "jaraco.classes",
"specs": [
[
"==",
"3.4.0"
]
]
},
{
"name": "jaraco.context",
"specs": [
[
"==",
"6.0.1"
]
]
},
{
"name": "jaraco.functools",
"specs": [
[
"==",
"4.3.0"
]
]
},
{
"name": "Jinja2",
"specs": [
[
"==",
"3.1.6"
]
]
},
{
"name": "jsonschema",
"specs": [
[
"==",
"4.25.1"
]
]
},
{
"name": "jsonschema-specifications",
"specs": [
[
"==",
"2025.9.1"
]
]
},
{
"name": "keyring",
"specs": [
[
"==",
"25.6.0"
]
]
},
{
"name": "Markdown",
"specs": [
[
"==",
"3.10"
]
]
},
{
"name": "markdown-it-py",
"specs": [
[
"==",
"4.0.0"
]
]
},
{
"name": "MarkupSafe",
"specs": [
[
"==",
"3.0.3"
]
]
},
{
"name": "mccabe",
"specs": [
[
"==",
"0.7.0"
]
]
},
{
"name": "mdurl",
"specs": [
[
"==",
"0.1.2"
]
]
},
{
"name": "more-itertools",
"specs": [
[
"==",
"10.8.0"
]
]
},
{
"name": "mypy_extensions",
"specs": [
[
"==",
"1.1.0"
]
]
},
{
"name": "narwhals",
"specs": [
[
"==",
"2.11.0"
]
]
},
{
"name": "nh3",
"specs": [
[
"==",
"0.3.2"
]
]
},
{
"name": "numpy",
"specs": [
[
"==",
"2.3.4"
]
]
},
{
"name": "packaging",
"specs": [
[
"==",
"25.0"
]
]
},
{
"name": "pandas",
"specs": [
[
"==",
"2.3.3"
]
]
},
{
"name": "pathspec",
"specs": [
[
"==",
"0.12.1"
]
]
},
{
"name": "pillow",
"specs": [
[
"==",
"12.0.0"
]
]
},
{
"name": "platformdirs",
"specs": [
[
"==",
"4.5.0"
]
]
},
{
"name": "pluggy",
"specs": [
[
"==",
"1.6.0"
]
]
},
{
"name": "protobuf",
"specs": [
[
"==",
"6.33.0"
]
]
},
{
"name": "pyarrow",
"specs": [
[
"==",
"21.0.0"
]
]
},
{
"name": "pycodestyle",
"specs": [
[
"==",
"2.14.0"
]
]
},
{
"name": "pydeck",
"specs": [
[
"==",
"0.9.1"
]
]
},
{
"name": "pyflakes",
"specs": [
[
"==",
"3.4.0"
]
]
},
{
"name": "Pygments",
"specs": [
[
"==",
"2.19.2"
]
]
},
{
"name": "pyproject_hooks",
"specs": [
[
"==",
"1.2.0"
]
]
},
{
"name": "pytest",
"specs": [
[
"==",
"9.0.1"
]
]
},
{
"name": "python-dateutil",
"specs": [
[
"==",
"2.9.0.post0"
]
]
},
{
"name": "pytokens",
"specs": [
[
"==",
"0.3.0"
]
]
},
{
"name": "pytz",
"specs": [
[
"==",
"2025.2"
]
]
},
{
"name": "readme_renderer",
"specs": [
[
"==",
"44.0"
]
]
},
{
"name": "referencing",
"specs": [
[
"==",
"0.37.0"
]
]
},
{
"name": "requests",
"specs": [
[
"==",
"2.32.5"
]
]
},
{
"name": "requests-toolbelt",
"specs": [
[
"==",
"1.0.0"
]
]
},
{
"name": "rfc3986",
"specs": [
[
"==",
"2.0.0"
]
]
},
{
"name": "rich",
"specs": [
[
"==",
"14.2.0"
]
]
},
{
"name": "rpds-py",
"specs": [
[
"==",
"0.28.0"
]
]
},
{
"name": "setuptools",
"specs": [
[
"==",
"80.9.0"
]
]
},
{
"name": "six",
"specs": [
[
"==",
"1.17.0"
]
]
},
{
"name": "smmap",
"specs": [
[
"==",
"5.0.2"
]
]
},
{
"name": "streamlit",
"specs": [
[
"==",
"1.51.0"
]
]
},
{
"name": "tenacity",
"specs": [
[
"==",
"9.1.2"
]
]
},
{
"name": "toml",
"specs": [
[
"==",
"0.10.2"
]
]
},
{
"name": "tornado",
"specs": [
[
"==",
"6.5.2"
]
]
},
{
"name": "twine",
"specs": [
[
"==",
"6.2.0"
]
]
},
{
"name": "typing_extensions",
"specs": [
[
"==",
"4.15.0"
]
]
},
{
"name": "tzdata",
"specs": [
[
"==",
"2025.2"
]
]
},
{
"name": "urllib3",
"specs": [
[
"==",
"2.5.0"
]
]
},
{
"name": "wheel",
"specs": [
[
"==",
"0.45.1"
]
]
}
],
"lcname": "sahajmails"
}