Skip to content

refactor(api): type SMTP mail payload with TypedDict#35174

Open
YB0y wants to merge 3 commits intolanggenius:mainfrom
YB0y:refactor/typed-dict-smtp-message
Open

refactor(api): type SMTP mail payload with TypedDict#35174
YB0y wants to merge 3 commits intolanggenius:mainfrom
YB0y:refactor/typed-dict-smtp-message

Conversation

@YB0y
Copy link
Copy Markdown
Contributor

@YB0y YB0y commented Apr 14, 2026

Part of #32863 (api/libs/)

Summary

  • Define SMTPMessageDict TypedDict for the SMTP mail payload
  • Replace the generic dict parameter annotation on SMTPClient.send() with SMTPMessageDict

Why this change

SMTPClient.send() accepted a plain dict, even though it relies on a fixed 3-key payload shape (to, subject, html). That hid the contract from type checkers and readers. A TypedDict makes the expected payload explicit without changing runtime behavior.

Changes

  • api/libs/smtp.py: Define SMTPMessageDict, annotate SMTPClient.send() to accept it

@dosubot dosubot bot added size:XS This PR changes 0-9 lines, ignoring generated files. refactor labels Apr 14, 2026
@YB0y YB0y requested a review from QuantumGhost as a code owner April 14, 2026 12:32
@dosubot dosubot bot added size:S This PR changes 10-29 lines, ignoring generated files. and removed size:XS This PR changes 0-9 lines, ignoring generated files. labels Apr 14, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Pyrefly Diff

base → PR
--- /tmp/pyrefly_base.txt	2026-04-14 12:34:22.765817474 +0000
+++ /tmp/pyrefly_pr.txt	2026-04-14 12:34:12.243727180 +0000
@@ -5890,6 +5890,16 @@
   --> tests/unit_tests/libs/test_rate_limiter.py:42:22
 ERROR Argument `dict[@_, @_]` is not assignable to parameter `headers` with type `Message` in function `python_http_client.exceptions.HTTPError.__init__` [bad-argument-type]
   --> tests/unit_tests/libs/test_sendgrid_client.py:38:99
+ERROR Argument `dict[Unknown, Unknown]` is not assignable to parameter `mail` with type `SMTPMessageDict` in function `libs.smtp.SMTPClient.send` [bad-argument-type]
+  --> tests/unit_tests/libs/test_smtp_client.py:16:17
+ERROR Argument `dict[Unknown, Unknown]` is not assignable to parameter `mail` with type `SMTPMessageDict` in function `libs.smtp.SMTPClient.send` [bad-argument-type]
+  --> tests/unit_tests/libs/test_smtp_client.py:35:17
+ERROR Argument `dict[Unknown, Unknown]` is not assignable to parameter `mail` with type `SMTPMessageDict` in function `libs.smtp.SMTPClient.send` [bad-argument-type]
+  --> tests/unit_tests/libs/test_smtp_client.py:62:21
+ERROR Argument `dict[Unknown, Unknown]` is not assignable to parameter `mail` with type `SMTPMessageDict` in function `libs.smtp.SMTPClient.send` [bad-argument-type]
+  --> tests/unit_tests/libs/test_smtp_client.py:74:21
+ERROR Argument `dict[Unknown, Unknown]` is not assignable to parameter `mail` with type `SMTPMessageDict` in function `libs.smtp.SMTPClient.send` [bad-argument-type]
+  --> tests/unit_tests/libs/test_smtp_client.py:95:21
 ERROR Argument `None` is not assignable to parameter `duration_str` with type `str` in function `libs.time_parser.parse_time_duration` [bad-argument-type]
   --> tests/unit_tests/libs/test_time_parser.py:54:38
 ERROR Argument `MockRequest` is not assignable to parameter `request` with type `Request` in function `libs.token.extract_access_token` [bad-argument-type]

@YB0y YB0y force-pushed the refactor/typed-dict-smtp-message branch from 830dbbf to a7a7dec Compare April 14, 2026 12:39
@github-actions
Copy link
Copy Markdown
Contributor

Pyrefly Diff

base → PR
--- /tmp/pyrefly_base.txt	2026-04-14 12:45:51.907828339 +0000
+++ /tmp/pyrefly_pr.txt	2026-04-14 12:45:41.194917008 +0000
@@ -5890,6 +5890,16 @@
   --> tests/unit_tests/libs/test_rate_limiter.py:42:22
 ERROR Argument `dict[@_, @_]` is not assignable to parameter `headers` with type `Message` in function `python_http_client.exceptions.HTTPError.__init__` [bad-argument-type]
   --> tests/unit_tests/libs/test_sendgrid_client.py:38:99
+ERROR Argument `dict[Unknown, Unknown]` is not assignable to parameter `mail` with type `SMTPMessageDict` in function `libs.smtp.SMTPClient.send` [bad-argument-type]
+  --> tests/unit_tests/libs/test_smtp_client.py:16:17
+ERROR Argument `dict[Unknown, Unknown]` is not assignable to parameter `mail` with type `SMTPMessageDict` in function `libs.smtp.SMTPClient.send` [bad-argument-type]
+  --> tests/unit_tests/libs/test_smtp_client.py:35:17
+ERROR Argument `dict[Unknown, Unknown]` is not assignable to parameter `mail` with type `SMTPMessageDict` in function `libs.smtp.SMTPClient.send` [bad-argument-type]
+  --> tests/unit_tests/libs/test_smtp_client.py:62:21
+ERROR Argument `dict[Unknown, Unknown]` is not assignable to parameter `mail` with type `SMTPMessageDict` in function `libs.smtp.SMTPClient.send` [bad-argument-type]
+  --> tests/unit_tests/libs/test_smtp_client.py:74:21
+ERROR Argument `dict[Unknown, Unknown]` is not assignable to parameter `mail` with type `SMTPMessageDict` in function `libs.smtp.SMTPClient.send` [bad-argument-type]
+  --> tests/unit_tests/libs/test_smtp_client.py:95:21
 ERROR Argument `None` is not assignable to parameter `duration_str` with type `str` in function `libs.time_parser.parse_time_duration` [bad-argument-type]
   --> tests/unit_tests/libs/test_time_parser.py:54:38
 ERROR Argument `MockRequest` is not assignable to parameter `request` with type `Request` in function `libs.token.extract_access_token` [bad-argument-type]

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors the SMTP email sending API to use a TypedDict so the expected payload shape (to, subject, html) is explicit to type checkers and readers.

Changes:

  • Added SMTPMessageDict TypedDict to represent the SMTP mail payload.
  • Updated SMTPClient.send() to accept SMTPMessageDict and return None.
  • Updated Mail.send() to pass an SMTP-specific payload shape when the underlying client is SMTPClient.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
api/libs/smtp.py Introduces SMTPMessageDict and narrows SMTPClient.send()’s parameter type to this TypedDict.
api/extensions/ext_mail.py Imports the new TypedDict and routes SMTP sends through an SMTP-specific payload shape.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


from configs import dify_config
from dify_app import DifyApp
from libs.smtp import SMTPClient, SMTPMessageDict
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SMTPClient/SMTPMessageDict are now imported at module import time, but SMTPClient is also imported lazily inside init_app() for the SMTP case. This is redundant and also removes the previous lazy-load behavior for non-SMTP mail types. Consider keeping only one import strategy (e.g., keep the lazy import and remove the top-level import, or remove the inner import if you want eager import).

Copilot uses AI. Check for mistakes.
Comment on lines +92 to +96
SMTPMessageDict(
to=to,
subject=subject,
html=html,
)
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using SMTPMessageDict(...) as a runtime constructor is unnecessary here (TypedDict is primarily for static typing) and can be confusing to readers. Prefer constructing a normal dict literal and annotating/casting it to SMTPMessageDict before passing it to SMTPClient.send().

Copilot uses AI. Check for mistakes.
Comment on lines +91 to 100
self._client.send(
SMTPMessageDict(
to=to,
subject=subject,
html=html,
)
)
return

self._client.send(
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new SMTP-specific branch (isinstance(self._client, SMTPClient)) changes the runtime call path and payload shape passed to the client, but the existing Mail extension tests only exercise the generic MagicMock client path. Add a unit test that sets _client to an actual SMTPClient (mocking out smtplib) and asserts Mail.send() calls SMTPClient.send() with the expected 3-key payload and returns early.

Suggested change
self._client.send(
SMTPMessageDict(
to=to,
subject=subject,
html=html,
)
)
return
self._client.send(
return self._client.send(
SMTPMessageDict(
to=to,
subject=subject,
html=html,
)
)
return self._client.send(

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refactor size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants