coffeemail 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. coffeemail-0.1.0/.github/workflows/ci.yml +42 -0
  2. coffeemail-0.1.0/.github/workflows/publish.yml +61 -0
  3. coffeemail-0.1.0/.gitignore +69 -0
  4. coffeemail-0.1.0/PKG-INFO +179 -0
  5. coffeemail-0.1.0/README.md +147 -0
  6. coffeemail-0.1.0/pyproject.toml +97 -0
  7. coffeemail-0.1.0/specs/SDD_ROADMAP.md +98 -0
  8. coffeemail-0.1.0/specs/SPEC.md +142 -0
  9. coffeemail-0.1.0/src/coffeemail/__init__.py +106 -0
  10. coffeemail-0.1.0/src/coffeemail/async_client.py +52 -0
  11. coffeemail-0.1.0/src/coffeemail/client.py +50 -0
  12. coffeemail-0.1.0/src/coffeemail/core/crypto.py +19 -0
  13. coffeemail-0.1.0/src/coffeemail/core/errors.py +88 -0
  14. coffeemail-0.1.0/src/coffeemail/core/http.py +243 -0
  15. coffeemail-0.1.0/src/coffeemail/core/i18n.py +33 -0
  16. coffeemail-0.1.0/src/coffeemail/core/types.py +50 -0
  17. coffeemail-0.1.0/src/coffeemail/models/__init__.py +89 -0
  18. coffeemail-0.1.0/src/coffeemail/models/audiences.py +50 -0
  19. coffeemail-0.1.0/src/coffeemail/models/broadcasts.py +27 -0
  20. coffeemail-0.1.0/src/coffeemail/models/domains.py +43 -0
  21. coffeemail-0.1.0/src/coffeemail/models/emails.py +96 -0
  22. coffeemail-0.1.0/src/coffeemail/models/stats.py +16 -0
  23. coffeemail-0.1.0/src/coffeemail/models/suppressions.py +29 -0
  24. coffeemail-0.1.0/src/coffeemail/models/templates.py +31 -0
  25. coffeemail-0.1.0/src/coffeemail/models/webhooks.py +47 -0
  26. coffeemail-0.1.0/src/coffeemail/py.typed +1 -0
  27. coffeemail-0.1.0/src/coffeemail/resources/__init__.py +29 -0
  28. coffeemail-0.1.0/src/coffeemail/resources/audiences.py +307 -0
  29. coffeemail-0.1.0/src/coffeemail/resources/broadcasts.py +154 -0
  30. coffeemail-0.1.0/src/coffeemail/resources/domains.py +99 -0
  31. coffeemail-0.1.0/src/coffeemail/resources/emails.py +243 -0
  32. coffeemail-0.1.0/src/coffeemail/resources/stats.py +49 -0
  33. coffeemail-0.1.0/src/coffeemail/resources/suppressions.py +108 -0
  34. coffeemail-0.1.0/src/coffeemail/resources/templates.py +257 -0
  35. coffeemail-0.1.0/src/coffeemail/resources/webhooks.py +182 -0
  36. coffeemail-0.1.0/tests/conftest.py +6 -0
  37. coffeemail-0.1.0/tests/test_client.py +54 -0
  38. coffeemail-0.1.0/tests/test_crypto.py +30 -0
  39. coffeemail-0.1.0/tests/test_emails.py +40 -0
  40. coffeemail-0.1.0/uv.lock +751 -0
@@ -0,0 +1,42 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ validate:
11
+ name: Validate (lint + typecheck + test + build)
12
+ runs-on: ubuntu-latest
13
+
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - name: Install uv
18
+ uses: astral-sh/setup-uv@v5
19
+ with:
20
+ version: "latest"
21
+ enable-cache: true
22
+
23
+ - name: Set up Python
24
+ run: uv python install 3.10
25
+
26
+ - name: Install dependencies
27
+ run: uv sync --extra dev
28
+
29
+ - name: Check formatting with Ruff
30
+ run: uv run ruff format --check .
31
+
32
+ - name: Lint with Ruff
33
+ run: uv run ruff check .
34
+
35
+ - name: Typecheck with Mypy
36
+ run: uv run mypy src tests
37
+
38
+ - name: Run Tests
39
+ run: uv run pytest -v
40
+
41
+ - name: Build distribution package
42
+ run: uv build
@@ -0,0 +1,61 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ tags:
7
+ - "v*"
8
+
9
+ jobs:
10
+ validate-and-publish:
11
+ name: Build, verify and publish to PyPI
12
+ runs-on: ubuntu-latest
13
+ permissions:
14
+ contents: read
15
+ id-token: write # Necessário para Trusted Publishing (OIDC) no PyPI
16
+
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - name: Install uv
21
+ uses: astral-sh/setup-uv@v5
22
+ with:
23
+ version: "latest"
24
+ enable-cache: true
25
+
26
+ - name: Set up Python
27
+ run: uv python install 3.10
28
+
29
+ - name: Install dependencies
30
+ run: uv sync --extra dev
31
+
32
+ - name: Code quality and tests
33
+ run: |
34
+ uv run ruff format --check .
35
+ uv run ruff check .
36
+ uv run mypy src tests
37
+ uv run pytest -v
38
+
39
+ - name: Check if current version is already on PyPI
40
+ id: check_version
41
+ run: |
42
+ VERSION=$(python3 -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")
43
+ echo "Package version: $VERSION"
44
+ STATUS_CODE=$(curl -s -o /dev/null -w "%{http_code}" "https://pypi.org/pypi/coffeemail/$VERSION/json")
45
+ if [ "$STATUS_CODE" = "200" ]; then
46
+ echo "Version $VERSION is already published on PyPI. Skipping publication."
47
+ echo "should_publish=false" >> "$GITHUB_OUTPUT"
48
+ else
49
+ echo "New version $VERSION ready for publication."
50
+ echo "should_publish=true" >> "$GITHUB_OUTPUT"
51
+ fi
52
+
53
+ - name: Build distribution packages (wheel and sdist)
54
+ if: steps.check_version.outputs.should_publish == 'true'
55
+ run: uv build
56
+
57
+ - name: Publish to PyPI via Trusted Publishing
58
+ if: steps.check_version.outputs.should_publish == 'true'
59
+ uses: pypa/gh-action-pypi-publish@release/v1
60
+ with:
61
+ password: ${{ secrets.PYPI_API_TOKEN }}
@@ -0,0 +1,69 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # Virtual environments
30
+ .venv/
31
+ env/
32
+ venv/
33
+ ENV/
34
+ env.bak/
35
+ venv.bak/
36
+
37
+ # Testing and coverage
38
+ .tox/
39
+ .nox/
40
+ .coverage
41
+ .coverage.*
42
+ .cache
43
+ nosetests.xml
44
+ coverage.xml
45
+ *.cover
46
+ *.py,cover
47
+ .hypothesis/
48
+ .pytest_cache/
49
+ cover/
50
+
51
+ # Type checking & Linters
52
+ .mypy_cache/
53
+ .dmypy.json
54
+ dmypy.json
55
+ .pyre/
56
+ .pytype/
57
+ .ruff_cache/
58
+
59
+ # IDE & OS
60
+ .DS_Store
61
+ .idea/
62
+ .vscode/
63
+ *.sublime-project
64
+ *.sublime-workspace
65
+
66
+ # Environment variables
67
+ .env
68
+ .env.*
69
+ !.env.example
@@ -0,0 +1,179 @@
1
+ Metadata-Version: 2.5
2
+ Name: coffeemail
3
+ Version: 0.1.0
4
+ Summary: SDK oficial do CoffeeMail para Python (Síncrono e Assíncrono com tipagem estrita).
5
+ Project-URL: Homepage, https://coffeemail.com.br
6
+ Project-URL: Documentation, https://docs.coffeemail.com.br
7
+ Project-URL: Repository, https://github.com/coffeemail/coffee-mail-sdk-python
8
+ Author-email: CoffeeMail Team <contato@coffeemail.com.br>
9
+ License: MIT
10
+ Keywords: api,coffeemail,email,sdk,transactional
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Communications :: Email
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.10
21
+ Requires-Dist: httpx>=0.27.0
22
+ Requires-Dist: pydantic>=2.6.0
23
+ Requires-Dist: typing-extensions>=4.10.0
24
+ Provides-Extra: dev
25
+ Requires-Dist: mypy>=1.9.0; extra == 'dev'
26
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
27
+ Requires-Dist: pytest-mock>=3.12.0; extra == 'dev'
28
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
29
+ Requires-Dist: respx>=0.21.0; extra == 'dev'
30
+ Requires-Dist: ruff>=0.3.0; extra == 'dev'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # CoffeeMail Python SDK (`coffeemail`)
34
+
35
+ SDK oficial da **CoffeeMail** para Python, com suporte nativo a operações **Síncronas** e **Assíncronas**, tipagem estrita via **Pydantic v2**, compatibilidade total com PEP 561 (`py.typed`) e padrão de retorno seguro `{ data, error }`.
36
+
37
+ ---
38
+
39
+ ## 📦 Instalação
40
+
41
+ ```bash
42
+ pip install coffeemail
43
+ # ou utilizando uv:
44
+ uv add coffeemail
45
+ # ou utilizando poetry:
46
+ poetry add coffeemail
47
+ ```
48
+
49
+ ---
50
+
51
+ ## ⚡ Início Rápido
52
+
53
+ ### 1. Envio Transacional Síncrono (Django, Flask, Scripts)
54
+
55
+ ```python
56
+ from coffeemail import CoffeeMail
57
+
58
+ # Lê automaticamente a variável de ambiente COFFEEMAIL_API_KEY se omitida:
59
+ client = CoffeeMail()
60
+
61
+ data, error = client.emails.send(
62
+ {
63
+ "from": "contato@seudominio.com.br",
64
+ "to": "cliente@empresa.com",
65
+ "subject": "Boas-vindas ao CoffeeMail!",
66
+ "html": "<h1>Olá, seja bem-vindo!</h1>",
67
+ }
68
+ )
69
+
70
+ if error:
71
+ print(f"Erro ao disparar e-mail: {error.message}")
72
+ else:
73
+ print(f"E-mail enfileirado com sucesso! ID: {data.id}")
74
+ ```
75
+
76
+ ### 2. Envio Assíncrono de Alta Performance (FastAPI, Celery, Temporal)
77
+
78
+ ```python
79
+ import asyncio
80
+ from coffeemail import AsyncCoffeeMail
81
+
82
+
83
+ async def main():
84
+ client = AsyncCoffeeMail()
85
+
86
+ response = await client.emails.send(
87
+ {
88
+ "from": {"email": "notificacoes@seudominio.com.br", "name": "Notificações"},
89
+ "to": "destinatario@gmail.com",
90
+ "subject": "Sua fatura foi gerada",
91
+ "html": "<p>Acesse o painel para visualizar o boleto.</p>",
92
+ }
93
+ )
94
+
95
+ if response.error:
96
+ print(f"Falha: {response.error}")
97
+ return
98
+
99
+ print(f"Status do disparo: {response.data.status}")
100
+
101
+
102
+ asyncio.run(main())
103
+ ```
104
+
105
+ ---
106
+
107
+ ## 🛡️ Padrão de Resposta Seguro e Ergonomia
108
+
109
+ Todas as chamadas do SDK retornam uma instância de `CoffeeMailResponse[T]`. Você pode optar pelo estilo que melhor se adapta à sua equipe:
110
+
111
+ ### Desempacotamento de Tupla (Recomendado)
112
+ ```python
113
+ data, error = client.emails.get("msg_123")
114
+ if error:
115
+ print(f"Falha: {error}")
116
+ else:
117
+ print(f"Status: {data.status}")
118
+ ```
119
+
120
+ ### Método `.unwrap()` (Lança Exceção em Caso de Erro)
121
+ ```python
122
+ try:
123
+ email = client.emails.get("msg_123").unwrap()
124
+ print(f"Entregue em: {email.delivered_at}")
125
+ except CoffeeMailError as err:
126
+ print(f"Exceção capturada: {err}")
127
+ ```
128
+
129
+ ---
130
+
131
+ ## 🧩 Recursos Disponíveis
132
+
133
+ * **`emails`**: Disparo individual, em lote (`send_batch`), consulta de status, cancelamento de agendamentos e listagem de eventos.
134
+ * **`domains`**: Criação de domínios e verificação de registros DNS (SPF, DKIM, DMARC, MX).
135
+ * **`templates`**: Cadastro de modelos HTML, renderização de pré-visualização (`preview`) e envio de testes.
136
+ * **`audiences`**: Listas de contatos, inclusão em lote (`bulk_add`) e gestão de inscritos.
137
+ * **`broadcasts`**: Campanhas e envios em massa com agendamento.
138
+ * **`suppressions`**: Consulta e gerenciamento de lista de supressão (bounces e unsubscribes).
139
+ * **`webhooks`**: Gerenciamento de endpoints e validação criptográfica de assinaturas HMAC SHA-256.
140
+ * **`stats`**: Consulta de taxas de entrega, abertura e rejeição por período.
141
+
142
+ ---
143
+
144
+ ## 🔒 Validação Criptográfica de Webhooks
145
+
146
+ Proteja suas rotas contra requisições forjadas validando a assinatura enviada no header `x-coffeemail-signature`:
147
+
148
+ ```python
149
+ from coffeemail import Webhooks
150
+
151
+ is_valid = Webhooks.verify_signature(
152
+ payload=request_body_raw,
153
+ signature=headers.get("x-coffeemail-signature"),
154
+ secret="whsec_seu_segredo_cadastrado",
155
+ )
156
+
157
+ if not is_valid:
158
+ return {"error": "Assinatura inválida"}, 401
159
+ ```
160
+
161
+ ---
162
+
163
+ ## 🛠️ Desenvolvimento e Testes
164
+
165
+ Para contribuir ou rodar os testes localmente:
166
+
167
+ ```bash
168
+ # Instalar dependências de desenvolvimento com uv:
169
+ uv sync --extra dev
170
+
171
+ # Executar suíte de testes unitários:
172
+ uv run pytest
173
+
174
+ # Executar checagem estrita de tipos com mypy:
175
+ uv run mypy src
176
+
177
+ # Executar linter e formatação com ruff:
178
+ uv run ruff check .
179
+ ```
@@ -0,0 +1,147 @@
1
+ # CoffeeMail Python SDK (`coffeemail`)
2
+
3
+ SDK oficial da **CoffeeMail** para Python, com suporte nativo a operações **Síncronas** e **Assíncronas**, tipagem estrita via **Pydantic v2**, compatibilidade total com PEP 561 (`py.typed`) e padrão de retorno seguro `{ data, error }`.
4
+
5
+ ---
6
+
7
+ ## 📦 Instalação
8
+
9
+ ```bash
10
+ pip install coffeemail
11
+ # ou utilizando uv:
12
+ uv add coffeemail
13
+ # ou utilizando poetry:
14
+ poetry add coffeemail
15
+ ```
16
+
17
+ ---
18
+
19
+ ## ⚡ Início Rápido
20
+
21
+ ### 1. Envio Transacional Síncrono (Django, Flask, Scripts)
22
+
23
+ ```python
24
+ from coffeemail import CoffeeMail
25
+
26
+ # Lê automaticamente a variável de ambiente COFFEEMAIL_API_KEY se omitida:
27
+ client = CoffeeMail()
28
+
29
+ data, error = client.emails.send(
30
+ {
31
+ "from": "contato@seudominio.com.br",
32
+ "to": "cliente@empresa.com",
33
+ "subject": "Boas-vindas ao CoffeeMail!",
34
+ "html": "<h1>Olá, seja bem-vindo!</h1>",
35
+ }
36
+ )
37
+
38
+ if error:
39
+ print(f"Erro ao disparar e-mail: {error.message}")
40
+ else:
41
+ print(f"E-mail enfileirado com sucesso! ID: {data.id}")
42
+ ```
43
+
44
+ ### 2. Envio Assíncrono de Alta Performance (FastAPI, Celery, Temporal)
45
+
46
+ ```python
47
+ import asyncio
48
+ from coffeemail import AsyncCoffeeMail
49
+
50
+
51
+ async def main():
52
+ client = AsyncCoffeeMail()
53
+
54
+ response = await client.emails.send(
55
+ {
56
+ "from": {"email": "notificacoes@seudominio.com.br", "name": "Notificações"},
57
+ "to": "destinatario@gmail.com",
58
+ "subject": "Sua fatura foi gerada",
59
+ "html": "<p>Acesse o painel para visualizar o boleto.</p>",
60
+ }
61
+ )
62
+
63
+ if response.error:
64
+ print(f"Falha: {response.error}")
65
+ return
66
+
67
+ print(f"Status do disparo: {response.data.status}")
68
+
69
+
70
+ asyncio.run(main())
71
+ ```
72
+
73
+ ---
74
+
75
+ ## 🛡️ Padrão de Resposta Seguro e Ergonomia
76
+
77
+ Todas as chamadas do SDK retornam uma instância de `CoffeeMailResponse[T]`. Você pode optar pelo estilo que melhor se adapta à sua equipe:
78
+
79
+ ### Desempacotamento de Tupla (Recomendado)
80
+ ```python
81
+ data, error = client.emails.get("msg_123")
82
+ if error:
83
+ print(f"Falha: {error}")
84
+ else:
85
+ print(f"Status: {data.status}")
86
+ ```
87
+
88
+ ### Método `.unwrap()` (Lança Exceção em Caso de Erro)
89
+ ```python
90
+ try:
91
+ email = client.emails.get("msg_123").unwrap()
92
+ print(f"Entregue em: {email.delivered_at}")
93
+ except CoffeeMailError as err:
94
+ print(f"Exceção capturada: {err}")
95
+ ```
96
+
97
+ ---
98
+
99
+ ## 🧩 Recursos Disponíveis
100
+
101
+ * **`emails`**: Disparo individual, em lote (`send_batch`), consulta de status, cancelamento de agendamentos e listagem de eventos.
102
+ * **`domains`**: Criação de domínios e verificação de registros DNS (SPF, DKIM, DMARC, MX).
103
+ * **`templates`**: Cadastro de modelos HTML, renderização de pré-visualização (`preview`) e envio de testes.
104
+ * **`audiences`**: Listas de contatos, inclusão em lote (`bulk_add`) e gestão de inscritos.
105
+ * **`broadcasts`**: Campanhas e envios em massa com agendamento.
106
+ * **`suppressions`**: Consulta e gerenciamento de lista de supressão (bounces e unsubscribes).
107
+ * **`webhooks`**: Gerenciamento de endpoints e validação criptográfica de assinaturas HMAC SHA-256.
108
+ * **`stats`**: Consulta de taxas de entrega, abertura e rejeição por período.
109
+
110
+ ---
111
+
112
+ ## 🔒 Validação Criptográfica de Webhooks
113
+
114
+ Proteja suas rotas contra requisições forjadas validando a assinatura enviada no header `x-coffeemail-signature`:
115
+
116
+ ```python
117
+ from coffeemail import Webhooks
118
+
119
+ is_valid = Webhooks.verify_signature(
120
+ payload=request_body_raw,
121
+ signature=headers.get("x-coffeemail-signature"),
122
+ secret="whsec_seu_segredo_cadastrado",
123
+ )
124
+
125
+ if not is_valid:
126
+ return {"error": "Assinatura inválida"}, 401
127
+ ```
128
+
129
+ ---
130
+
131
+ ## 🛠️ Desenvolvimento e Testes
132
+
133
+ Para contribuir ou rodar os testes localmente:
134
+
135
+ ```bash
136
+ # Instalar dependências de desenvolvimento com uv:
137
+ uv sync --extra dev
138
+
139
+ # Executar suíte de testes unitários:
140
+ uv run pytest
141
+
142
+ # Executar checagem estrita de tipos com mypy:
143
+ uv run mypy src
144
+
145
+ # Executar linter e formatação com ruff:
146
+ uv run ruff check .
147
+ ```
@@ -0,0 +1,97 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "coffeemail"
7
+ version = "0.1.0"
8
+ description = "SDK oficial do CoffeeMail para Python (Síncrono e Assíncrono com tipagem estrita)."
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ requires-python = ">=3.10"
12
+ authors = [
13
+ { name = "CoffeeMail Team", email = "contato@coffeemail.com.br" },
14
+ ]
15
+ keywords = ["email", "transactional", "coffeemail", "sdk", "api"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Developers",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Topic :: Communications :: Email",
25
+ "Typing :: Typed",
26
+ ]
27
+ dependencies = [
28
+ "httpx>=0.27.0",
29
+ "pydantic>=2.6.0",
30
+ "typing-extensions>=4.10.0",
31
+ ]
32
+
33
+ [project.optional-dependencies]
34
+ dev = [
35
+ "mypy>=1.9.0",
36
+ "pytest>=8.0.0",
37
+ "pytest-asyncio>=0.23.0",
38
+ "pytest-mock>=3.12.0",
39
+ "respx>=0.21.0",
40
+ "ruff>=0.3.0",
41
+ ]
42
+
43
+ [project.urls]
44
+ Homepage = "https://coffeemail.com.br"
45
+ Documentation = "https://docs.coffeemail.com.br"
46
+ Repository = "https://github.com/coffeemail/coffee-mail-sdk-python"
47
+
48
+ [tool.hatch.build.targets.wheel]
49
+ packages = ["src/coffeemail"]
50
+
51
+ [tool.ruff]
52
+ line-length = 100
53
+ target-version = "py310"
54
+
55
+ [tool.ruff.lint]
56
+ select = [
57
+ "E", # pycodestyle errors
58
+ "W", # pycodestyle warnings
59
+ "F", # pyflakes
60
+ "I", # isort
61
+ "B", # flake8-bugbear
62
+ "C4", # flake8-comprehensions
63
+ "UP", # pyupgrade
64
+ "ARG", # flake8-unused-arguments
65
+ "SIM", # flake8-simplify
66
+ "TCH", # flake8-type-checking
67
+ ]
68
+ ignore = ["E501"]
69
+
70
+ [tool.ruff.lint.isort]
71
+ known-first-party = ["coffeemail"]
72
+
73
+ [tool.mypy]
74
+ plugins = ["pydantic.mypy"]
75
+ python_version = "3.10"
76
+ strict = true
77
+ warn_return_any = true
78
+ warn_unused_configs = true
79
+ disallow_untyped_defs = true
80
+ disallow_incomplete_defs = true
81
+ check_untyped_defs = true
82
+ disallow_untyped_decorators = true
83
+ no_implicit_optional = true
84
+ warn_redundant_casts = true
85
+ warn_unused_ignores = true
86
+ warn_no_return = true
87
+
88
+ [tool.pydantic-mypy]
89
+ init_forbid_extra = true
90
+ init_typed = true
91
+ warn_required_dynamic_aliases = true
92
+
93
+ [tool.pytest.ini_options]
94
+ minversion = "8.0"
95
+ addopts = "-ra -q --strict-markers"
96
+ testpaths = ["tests"]
97
+ asyncio_mode = "auto"
@@ -0,0 +1,98 @@
1
+ # Planejamento de Implementação SDD: CoffeeMail Python SDK
2
+
3
+ Este documento estabelece o cronograma de entrega baseado em **Spec-Driven Development (SDD)**, com critérios de aceite, etapas de validação e integração ao **CoffeeMail SDK Workbench**.
4
+
5
+ ---
6
+
7
+ ## 🎯 Metodologia de Trabalho
8
+
9
+ Cada fase segue o ciclo rigoroso de SDD:
10
+ 1. **Especificação do Contrato**: Validação de parâmetros, tipos Pydantic e assinaturas públicas.
11
+ 2. **Testes Unitários / Mock First**: Escrita dos testes com `pytest` e `respx` simulando respostas da API antes da implementação final.
12
+ 3. **Implementação da Lógica**: Desenvolvimento com Clean Code e SOLID, sem complexidade acidental.
13
+ 4. **Verificação Estrita**: Execução do linter `ruff` e do type checker `mypy --strict`.
14
+ 5. **Homologação no Workbench**: Conexão com o `runner-python` na porta 4002 para auditoria na interface visual.
15
+
16
+ ---
17
+
18
+ ## 📋 Fases do Roadmap
19
+
20
+ ### **Fase 1: Fundação do Core, Tipos e Clientes Base**
21
+ * **Objetivo**: Estruturar transporte HTTP resiliente (síncrono e assíncrono), envelope de resposta e autenticação.
22
+ * **Tarefas**:
23
+ - Implementar hierarquia de exceções em `coffeemail.core.errors`.
24
+ - Implementar envelope `CoffeeMailResponse[T]` com suporte a desempacotamento de tupla e `.unwrap()`.
25
+ - Implementar camada HTTP com `httpx.Client` e `httpx.AsyncClient` em `coffeemail.core.http`.
26
+ - Implementar cliente principal `CoffeeMail` e `AsyncCoffeeMail`.
27
+ - Implementar introspecção de chave `client.introspect()`.
28
+ * **Critérios de Aceite**:
29
+ - Testes passando com 100% de cobertura para validação de chave nula/inválida.
30
+ - Headers corretos (`User-Agent: coffeemail-python/0.1.0`, `Authorization`, `Accept-Language`).
31
+
32
+ ---
33
+
34
+ ### **Fase 2: Módulo de E-mails Transacionais (`emails`)**
35
+ * **Objetivo**: Implementar o principal recurso do SDK, cobrindo envios simples, em lote, consultas e eventos.
36
+ * **Tarefas**:
37
+ - Modelar DTOs Pydantic v2: `SendEmailPayload`, `SendEmailResponse`, `EmailDetail`, `BatchSendEmailResult`, etc.
38
+ - Implementar normalização de destinatários: aceitar string (`"user@dominio.com"`), dicionário (`{"name": "...", "email": "..."}`) ou listas de ambos.
39
+ - Implementar suporte a anexos: aceitar string base64, bytes brutos ou caminho de arquivo local (`pathlib.Path` / `str`).
40
+ - Implementar métodos: `send`, `send_batch`, `get`, `list`, `cancel`, `get_events`, `list_tags`.
41
+ * **Critérios de Aceite**:
42
+ - Mapeamento correto de `snake_case` para o payload `camelCase` esperado pela API CoffeeMail.
43
+ - Testes unitários com `respx` simulando requisições com múltiplos anexos e parâmetros de agendamento.
44
+
45
+ ---
46
+
47
+ ### **Fase 3: Módulos de Domínios (`domains`) e Webhooks (`webhooks`)**
48
+ * **Objetivo**: Configuração de remetentes autorizados e recebimento seguro de eventos.
49
+ * **Tarefas**:
50
+ - Implementar métodos de domínios: `list`, `get`, `create`, `verify`, `get_health`, `delete`.
51
+ - Implementar verificação de registros DNS (SPF, DKIM, DMARC, MX).
52
+ - Implementar gestão de endpoints de Webhook: `list`, `get`, `create`, `update`, `toggle`, `rotate_secret`, `test`, `list_deliveries`.
53
+ - Implementar utilitário criptográfico `webhooks.verify_signature` com verificação de timestamp e tolerância a drift de relógio.
54
+ * **Critérios de Aceite**:
55
+ - Testes unitários comprovando rejeição de assinaturas HMAC inválidas ou com timestamp expirado.
56
+
57
+ ---
58
+
59
+ ### **Fase 4: Modelos (`templates`) e Pré-visualização**
60
+ * **Objetivo**: Gestão de templates HTML e renderização de prévias.
61
+ * **Tarefas**:
62
+ - Implementar métodos: `list`, `get`, `create`, `update`, `delete`.
63
+ - Implementar `preview` suportando tanto ID de modelo existente quanto código HTML bruto com variáveis de substituição.
64
+ - Implementar `test_send` para envio de prova.
65
+ * **Critérios de Aceite**:
66
+ - Retorno consistente com envelopamento `{ templates: [...] }`.
67
+
68
+ ---
69
+
70
+ ### **Fase 5: Audiências (`audiences`), Contatos (`contacts`) e Campanhas (`broadcasts`)**
71
+ * **Objetivo**: Gerenciamento de listas de e-mail e envios em massa.
72
+ * **Tarefas**:
73
+ - Implementar gestão de audiências e contatos aninhados (`audiences.contacts`).
74
+ - Adicionar atalhos ergonômicos no topo de `audiences` (`list_contacts`, `create_contact`, `bulk_add_contacts`).
75
+ - Implementar módulo de campanhas `broadcasts` (`list`, `get`, `create`, `send`, `cancel`, `delete`).
76
+ * **Critérios de Aceite**:
77
+ - Tipagem completa de atributos personalizados de contatos (`attributes: dict[str, Any]`).
78
+
79
+ ---
80
+
81
+ ### **Fase 6: Supressões (`suppressions`) e Estatísticas (`stats`)**
82
+ * **Objetivo**: Controle de reputação de remetente e visualização analítica.
83
+ * **Tarefas**:
84
+ - Implementar `suppressions` para consulta e exclusão de bounces/unsubscribes.
85
+ - Implementar `stats` para recuperação de taxas de abertura, entrega e rejeição por período.
86
+ * **Critérios de Aceite**:
87
+ - Validação de formatação de datas ISO 8601 nos filtros de estatísticas.
88
+
89
+ ---
90
+
91
+ ### **Fase 7: Integração com o Workbench e Runner Python**
92
+ * **Objetivo**: Criar o backend `coffee-mail-sdk-workbench/backends/runner-python` consumindo o pacote local.
93
+ * **Tarefas**:
94
+ - Criar mini-backend em FastAPI ou Flask na porta 4002 implementando a Runner Specification API.
95
+ - Habilitar o seletor "Python Runner" no front-end web do Workbench.
96
+ - Executar bateria completa de testes de ponta a ponta na interface visual.
97
+ * **Critérios de Aceite**:
98
+ - 100% dos botões e formulários do Workbench funcionando igualmente no Runner Node e no Runner Python.