diff --git a/CHANGELOG.md b/CHANGELOG.md index 17ee02b..c8ef131 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Unreleased ---------- * UAS multi-credential update * Added `specific_time_availability` field to `AvailabilityParticipant` for overriding open hours on specific dates +* Added `smtp_required` option to hosted authentication config to require users to enter SMTP settings during IMAP authentication v6.14.2 ---------- diff --git a/nylas/models/auth.py b/nylas/models/auth.py index 2246478..6c83628 100644 --- a/nylas/models/auth.py +++ b/nylas/models/auth.py @@ -36,6 +36,8 @@ class URLForAuthenticationConfig(TypedDict): state: Optional state to be returned after authentication login_hint: Prefill the login name (usually email) during authorization flow. If a Grant for the provided email already exists, a Grant's re-auth will automatically be initiated. + smtp_required: If True, adds options=smtp_required so users must enter SMTP settings during + authentication. Relevant for IMAP; avoids grant errors when sending email later. """ client_id: str @@ -48,6 +50,7 @@ class URLForAuthenticationConfig(TypedDict): state: NotRequired[str] login_hint: NotRequired[str] credential_id: NotRequired[str] + smtp_required: NotRequired[bool] class URLForAdminConsentConfig(URLForAuthenticationConfig): diff --git a/nylas/resources/auth.py b/nylas/resources/auth.py index 18dfc65..6129bb2 100644 --- a/nylas/resources/auth.py +++ b/nylas/resources/auth.py @@ -35,6 +35,9 @@ def _build_query(config: dict) -> dict: if "scope" in config: config["scope"] = " ".join(config["scope"]) + if config.pop("smtp_required", None): + config["options"] = "smtp_required" + return config diff --git a/tests/resources/test_auth.py b/tests/resources/test_auth.py index f592de8..8548c34 100644 --- a/tests/resources/test_auth.py +++ b/tests/resources/test_auth.py @@ -37,6 +37,30 @@ def test_build_query(self): "scope": "email calendar", } + def test_build_query_with_smtp_required_true(self): + config = { + "foo": "bar", + "scope": ["email"], + "smtp_required": True, + } + result = _build_query(config) + assert result["options"] == "smtp_required" + assert "smtp_required" not in result # must not leak into URL params + + def test_build_query_smtp_required_false_omits_options(self): + config = { + "foo": "bar", + "scope": ["email"], + "smtp_required": False, + } + result = _build_query(config) + assert "options" not in result + + def test_build_query_smtp_required_omitted_omits_options(self): + config = {"foo": "bar", "scope": ["email"]} + result = _build_query(config) + assert "options" not in result + def test_build_query_with_pkce(self): config = { "foo": "bar", @@ -52,6 +76,18 @@ def test_build_query_with_pkce(self): "code_challenge_method": "s256", } + def test_build_query_with_pkce_and_smtp_required(self): + config = { + "foo": "bar", + "scope": ["email"], + "smtp_required": True, + } + result = _build_query_with_pkce(config, "secret-hash-123") + assert result["options"] == "smtp_required" + assert "smtp_required" not in result # must not leak into URL params + assert result["code_challenge"] == "secret-hash-123" + assert result["code_challenge_method"] == "s256" + def test_build_query_with_admin_consent(self): config = { "foo": "bar",