openemail.security
この名前空間のすべてのメソッドの、シグネチャ、パラメーター、戻り値、例。
メソッド
Verification codes for apps connected with OAuth: check whether sensitive changes are unlocked, ask for a code and verify it. API keys are never asked for one.
security.step_up_status()
Check whether an OAuth token is verified for sensitive changes
def step_up_status( *, api_key: str | None = None, timeout: float | None = None,) -> StepUpStatusResourceTells an app connected with OAuth whether it may make sensitive changes right now. The web app asks a person for a verification code before a change that could lock them out or leak mail, and an app acting for that person is asked the same thing. An API key is never asked, so this call is for OAuth access tokens only.
elevated is True while a code verified through verify_step_up still holds, and elevatedUntil says when that ends, or is None when there is nothing to end. The elevation belongs to this app acting for this person, and it holds for the app's MCP calls as well as for REST: the MCP tools that make the same guarded changes, such as createRule and removeDomain, run while it lasts. Another app they connected has to verify on its own, and signing in to the web app does not count here. The person can also allow this app from the website, with Allow changes for 60 minutes on the app in Account settings, Connected apps, and elevated is then True here as well.
method is how the next code would be checked. It is totp when the person has two-factor sign-in turned on, and then the code comes from their authenticator app, or is one of their backup codes. Otherwise it is email, and begin_step_up emails a code to the address they sign in with. minutes is how long an elevation lasts once a code is verified, currently 60.
Call it before a batch of sensitive changes to ask for a code once, up front, rather than waiting for the first call to raise OpenEmailApiError with is_step_up_required, the 403 step_up_required.
パラメーター
api_keystrSends this API key instead of the client's credential for this call only. A key is answered 400
step_up_not_applicable.timeoutfloatSeconds this call may take, the response included, before it raises
OpenEmailNetworkErrorwithis_timeout. It overrides the client'stimeoutfor this call, and0turns the limit off.
戻り値
StepUpStatusResource with object set to step_up, elevated, elevatedUntil, method and minutes.
例
from openemail import openemail status = openemail.security.step_up_status() if status['elevated']: print('Sensitive changes are unlocked until', status['elevatedUntil'])else: source = 'your authenticator app' if status['method'] == 'totp' else 'your email' print(f'Changes need a code from {source}')注意事項
It needs no scope. Any access token the server accepts may ask about itself.
An API key is refused with 400
step_up_not_applicable. Keys are never asked for a code, so there is nothing to check.Reading the status changes nothing and sends nothing, so it is safe to call as often as you like.
It does not report a pause. After 10 wrong codes in 24 hours from this app, or 20 from all of the person's apps together,
begin_step_upandverify_step_upraise 429step_up_locked, and only the error message says when verification resumes.
ほかの提供先
- API
GET /security/step-up- TypeScript
security.stepUpStatus()- Ruby
security.step_up_status
security.begin_step_up()
Ask for a verification code
def begin_step_up( body: StepUpBegin | None = None, *, api_key: str | None = None, timeout: float | None = None,) -> StepUpChallengeResourceOpens a verification challenge for an app connected with OAuth. Call it when a request raises OpenEmailApiError with is_step_up_required, the 403 step_up_required, or before a batch of sensitive changes, then pass the code the person gives you to verify_step_up and replay the request.
method says where the code comes from. With email a six digit code has just gone to the address the person signs in with, sentTo names that address with most of it hidden, such as a•••@example.com, and the code works for 10 minutes. The email says a connected app asked for the code and shows the name this app registered with, its client ID, the date the person connected it and, when the app was refused one in the last 15 minutes, the change it last asked to make, so they can see which app is asking before they hand the code over. It also tells them the code unlocks more than one change: for 60 minutes the app can make any change that needs a code and that they gave it access to. With totp nothing is sent: the person has two-factor sign-in turned on and reads the code from their authenticator app, or uses one of their backup codes.
A challenge that is still open and still has tries left is reused rather than replaced, so calling this twice does not send two emails. reused is True when that happened, and the code sent the first time is the one to enter. Pass {'resend': True} to close the open challenge and start a new one, which emails a fresh code. A challenge that five wrong codes locked is never reused, and neither is one that expired, so after step_up_code_expired, or after the fifth wrong code, a plain begin_step_up() starts a fresh challenge without resend.
Each app has a budget of its own with each person: 5 new challenges an hour and 20 in 24 hours. Another app never uses it up, and neither does the person working in the web app, whose own budget is 10 codes an hour.
Wrong codes count against the app too. After 10 in 24 hours, across every challenge it opened, verification is paused for this app. After 20 in 24 hours from all the apps the person connected together, it is paused for every one of them, this app included, even if none of those codes came from it, and removing an app does not lift that pause. Codes entered in the web app count toward neither, and the person can still verify there. While a pause lasts, this call and verify_step_up raise 429 step_up_locked with a message that says verification is paused until a given time, and no code is sent or checked before then.
An API key is never asked for a code, so this call is for OAuth access tokens only.
パラメーター
body['resend']boolCloses the open challenge and starts a new one, emailing a fresh code when the method is
email. Leave it out to reuse a challenge that is still open and still has tries left. A locked or expired challenge is replaced either way, and every new challenge counts toward the app's 5 an hour and 20 in 24 hours.api_keystrSends this API key instead of the client's credential for this call only. A key is answered 400
step_up_not_applicable.timeoutfloatSeconds this call may take, the response included, before it raises
OpenEmailNetworkErrorwithis_timeout. It overrides the client'stimeoutfor this call, and0turns the limit off.
戻り値
StepUpChallengeResource with object set to step_up_challenge, method, reused, and sentTo, the masked address, when the code went out by email. Read it with challenge.get('sentTo'), since a totp challenge has no such key.
例
from openemail import openemail challenge = openemail.security.begin_step_up() if challenge['method'] == 'email': print('We emailed a code to', challenge.get('sentTo'))else: print('Enter the code from your authenticator app, or a backup code.') fresh = openemail.security.begin_step_up({'resend': True})print(fresh['reused'])注意事項
It needs no scope. An API key is refused with 400
step_up_not_applicable.An app can open 5 challenges an hour and 20 in 24 hours for each person. The next is refused with 429
step_up_throttled, and the message says when to try again. A reused challenge does not count, and neither does one whose email could not be delivered. Other apps have budgets of their own, and so does the web app, which allows 10 an hour.After 10 wrong codes in 24 hours this app is paused, and after 20 from all of the person's apps together every app is: 429
step_up_locked, with a message that says verification is paused until a given time.{'resend': True}lifts neither pause. The person gets one email about each.When the email cannot be delivered the answer is 503
step_up_undeliverableand no challenge is left open. Try again in a moment.Not retried automatically, because a retry after a lost response could send a second email.
ほかの提供先
- API
POST /security/step-up- TypeScript
security.beginStepUp()- Ruby
security.begin_step_up
security.verify_step_up()
Verify a code and unlock sensitive changes
def verify_step_up( body: StepUpVerify, *, api_key: str | None = None, timeout: float | None = None,) -> StepUpVerifiedResourceChecks the code the person entered against the challenge begin_step_up opened, and on a match lets this app make sensitive changes for them until elevatedUntil, 60 minutes from now. Replay the request that raised OpenEmailApiError with is_step_up_required once this returns.
The verification belongs to this app acting for this person. It unlocks the 38 calls that ask for a code: webhooks.create, webhooks.update, rules.create, rules.update, roles.update, roles.delete, members.add, members.update, members.remove, members.grant_address, members.revoke_address, members.grant_domain, members.revoke_domain, domains.delete, domains.delete_address, domains.update_address, domains.add_address_forwards, domains.update_address_forward, domains.delete_address_forward, domains.resend_address_forward_consent, domains.set_address_login, domains.set_dns_zone, domains.sync_dns, dns_connections.delete, app_host.set, app_host.delete, audiences.delete, forms.delete, encryption.publish_key, exports.start, exports.download, billing.set_pay_as_you_go, billing.set_pay_as_you_go_limit, billing.confirm_pay_as_you_go, billing.start_checkout, billing.open_portal, billing.save_invoice_details and workspaces.delete. Three of them ask only in one case: domains.update_address when it changes destination, app_host.set when it replaces a host the workspace already has, and audiences.delete on any audience but the default one. Each still needs the scope it always needs. It holds for the MCP tools that make the same changes as well, such as createRule, setRuleEnabled, removeDomain, removeDomainAddress, removeAppHost, deleteForm, and deleteAudience on any audience but the default one, which answer Refused (step_up_required) while the app is not verified. Nothing else asks for a code, audiences.empty and the emptyAudience tool included. Another app the person connected verifies on its own.
The code is the one emailed to them when the method is email, or a code from their authenticator app, or one of their backup codes, when it is totp. Spaces are ignored, so a code copied as 123 456 works. An authenticator code is accepted only once: entering one that was already accepted, by any app or in the web app, counts as a wrong code, so wait for the next one.
Open a challenge with begin_step_up first, even when the code comes from an authenticator app, because the code is checked against that challenge. A challenge allows five tries. The fifth wrong code locks it, and a locked challenge is never reused, so the next begin_step_up() starts a fresh one without resend.
Wrong codes also count against this app for 24 hours, across every challenge, and a correct code does not clear them. The tenth in 24 hours pauses verification for this app. They count toward a second limit as well, shared by every app the person connected: the twentieth wrong code in 24 hours from all of those apps together pauses verification for every one of them, this app included, even if none of those codes came from it. Removing an app from the person's connected apps does not lift that pause. Codes entered in the web app count toward neither limit, and the person can still verify there during either pause. While a pause lasts, this call and begin_step_up raise 429 step_up_locked with a message that says verification is paused until a given time, and until then even a correct code is refused.
An app that has no way to ask the person for a code, such as an MCP connector that only calls tools, does not need this call: the person can choose Allow changes for 60 minutes on the app in Account settings, Connected apps, on the website, which lets it make the same changes for 60 minutes. They can end that early from the same menu.
An API key is never asked for a code, so this call is for OAuth access tokens only.
パラメーター
body['code']str必須The code the person entered: six digits from the email or their authenticator app, or one of their backup codes. 6 to 12 characters once surrounding spaces are trimmed.
api_keystrSends this API key instead of the client's credential for this call only. A key is answered 400
step_up_not_applicable.timeoutfloatSeconds this call may take, the response included, before it raises
OpenEmailNetworkErrorwithis_timeout. It overrides the client'stimeoutfor this call, and0turns the limit off.
戻り値
StepUpVerifiedResource with object set to step_up, elevated set to True and elevatedUntil, 60 minutes from now.
例
from openemail import OpenEmailApiError, openemail openemail.security.begin_step_up() try: verified = openemail.security.verify_step_up({'code': input('Verification code: ')})except OpenEmailApiError as error: if error.code != 'step_up_code_invalid': raise print(error.message)else: print('Unlocked until', verified['elevatedUntil']) openemail.webhooks.update('whe_3f9c2a7b1e4d8f60a5c7b92d', {'enabled': False})注意事項
It needs no scope. An API key is refused with 400
step_up_not_applicable.A wrong code is 400
step_up_code_invalid, withparamset tocode. The message says how many tries are left: the fewest of the tries left on this challenge, the wrong codes left before this app is paused and the wrong codes left before every app is paused.The fifth wrong code on a challenge, and every code sent after it, is 429
step_up_locked. Ask for a new code withbegin_step_up(), which starts a fresh challenge withoutresend.The tenth wrong code from this app in 24 hours is 429
step_up_lockedas well, and so is the twentieth from all of the person's apps together, and every call while either pause lasts. The message says verification is paused until a given time, which is how to tell a pause from a locked challenge, and it reads the same for both pauses. The person gets one email about each pause. The one for this app names it. The one for every app says codes from all the apps they connected are paused, names the app the last wrong code came from, and says codes entered on the website still work.An expired code, or no open challenge at all, is 400
step_up_code_expired. Ask for a new code withbegin_step_up().A code shorter than 6 or longer than 12 characters, or a body with any key besides
code, is refused before it is checked and does not use up a try.Not retried automatically. A retry after a lost response would spend a second attempt on a challenge the first one may already have closed.