Zur Dokumentation springen
Ruby

Konfiguration

Drei Wege, einen Client zu erzeugen, alle Optionen und was er ablehnt, bevor eine Anfrage gesendet wird.

Optionen

clients.rb
require "openemail" OpenEmail.init(api_key: ENV.fetch("OPENEMAIL_API_KEY"))OpenEmail.me.ping pinned = OpenEmail::Client.new(api_key: ENV.fetch("OPENEMAIL_API_KEY"), base_url: "https://api.openemail.uk")quick = OpenEmail::Client.new(ENV.fetch("OPENEMAIL_API_KEY"))billing = OpenEmail.create_client(api_key: ENV.fetch("BILLING_API_KEY")) p pinned.mode, quick.mode, billing.mode
EinstiegspunktWas Sie damit erhalten
OpenEmail.init(...)Konfiguriert den gemeinsamen Client und gibt ihn zurück. OpenEmail.client ist von da an dieser Client, in jeder Datei und jedem Thread, und alles, was Sie weglassen, wird aus der Umgebung gelesen.
OpenEmail.client, OpenEmail.emails, OpenEmail.threads und jeder andere NamespaceDer gemeinsame Client und Abkürzungen zu seinen Namespaces. Wird er vor init verwendet, baut er sich beim ersten Aufruf selbst aus OPENEMAIL_API_KEY und OPENEMAIL_BASE_URL.
OpenEmail.reset_clientVerwirft den gemeinsamen Client, sodass der nächste Aufruf einen neuen aus der Umgebung baut.
OpenEmail.create_client(...)Ein separater Client mit demselben Rückgriff auf die Umgebung, für einen zweiten Schlüssel neben dem gemeinsamen oder für einen Client, den Ihr eigener Code hält und weiterreicht.
OpenEmail::Client.new(...) or OpenEmail::Client.new(api_key)Ein separater Client, der genau aus dem gebaut wird, was Sie übergeben. Er liest keine Umgebung und braucht daher api_key: oder access_token:. OpenEmail.new ist derselbe Aufruf.
options.rb
OpenEmail.init(  api_key: ENV.fetch("OPENEMAIL_API_KEY"),  base_url: "https://api.openemail.uk",  timeout: 30,  max_retries: 2,  adapter: OpenEmail::NetHttpAdapter.new(max_idle: 8, keep_alive_timeout: 2),  headers: {"X-Team" => "billing"},  user_agent: "billing-service/1.4",  disable_update_notice: true)
OptionStandardHinweise
api_key:OPENEMAIL_API_KEYWird von init, create_client und dem gemeinsamen Client aus der Umgebung gelesen. Muss mit oe_live_ oder oe_test_ beginnen. Kann auch als erstes Argument übergeben werden, aber nicht beides.
access_token:OPENEMAIL_ACCESS_TOKENEin OAuth-Zugriffstoken oder alles, was auf call antwortet und eines zurückgibt. Siehe OAuth-Zugriffstoken weiter unten. Übergeben Sie einen Schlüssel oder ein Token, nie beides.
base_url:https://api.openemail.ukOder OPENEMAIL_BASE_URL. Abschließende Schrägstriche werden entfernt, und init und create_client setzen https:// vor einen bloßen Host oder http:// vor einen Host auf diesem Rechner: localhost, eine 127.x.x.x-Adresse oder ::1. Zugangsdaten werden nie über einfaches http an einen anderen Host gesendet, und 0.0.0.0 oder [::] löst beim Erzeugen des Clients einen Fehler aus, weil das Adressen sind, auf denen ein Server lauscht, und keine, an die man Anfragen sendet.
timeout:30Sekunden pro Versuch, nicht pro Aufruf. Mit dem Standardadapter umfasst das den Verbindungsaufbau und das Lesen des gesamten Bodys, nicht nur der Header. 0 schaltet es ab. files.upload wartet mindestens 600 Sekunden, sofern Sie bei diesem Aufruf nicht timeout: übergeben.
max_retries:2Zusätzliche Versuche nach dem ersten, bei Aufrufen, die gefahrlos wiederholt werden können. Wird am Client gesetzt, nicht pro Aufruf. 0 schaltet Wiederholungsversuche ab.
adapter:OpenEmail::NetHttpAdapter.newDie HTTP-Schicht. Der Standard hält bis zu 8 ungenutzte Verbindungen pro Host jeweils 2 Sekunden lang offen, und max_idle: und keep_alive_timeout: ändern das. Alles, was auf call(request) antwortet, kann an ihre Stelle treten. So läuft ein Test ohne Netzwerk.
headers:{}Werden bei jeder Anfrage gesendet.
user_agent:openemail-ruby/<version>Werden bei jeder Anfrage gesendet.
disable_update_notice:falseÜberspringt die einmal pro Prozess laufende Prüfung auf eine neuere Version bei RubyGems. Die Prüfung läuft nur, wenn die Standardausgabe ein Terminal ist, und OPENEMAIL_DISABLE_UPDATE_NOTICE schaltet sie ebenfalls ab.

Umgebungsvariablen

VariableWas es tut
OPENEMAIL_API_KEYDer Schlüssel, den init, create_client und der gemeinsame Client verwenden, wenn Sie weder api_key: noch access_token: übergeben.
OPENEMAIL_ACCESS_TOKENEin OAuth-Zugriffstoken, das nur gelesen wird, wenn Sie keinen der beiden Zugänge übergeben und OPENEMAIL_API_KEY nicht gesetzt ist. Ein Schlüssel in der Umgebung hat also Vorrang.
OPENEMAIL_BASE_URLDie Basis-URL, wenn Sie keine übergeben. Einem bloßen Host wie localhost:2222 wird das Schema hinzugefügt.
OPENEMAIL_DISABLE_UPDATE_NOTICEJeder nicht leere Wert schaltet den Update-Hinweis ab, für jeden Client im Prozess.
HTTPS_PROXY und NO_PROXY oder https_proxy und no_proxyDer Proxy, über den der Standardadapter verbindet, und die Hosts, die direkt erreicht werden. Siehe Proxys weiter unten.

OpenEmail::Client.new liest keine der ersten drei, ein so erzeugter Client übernimmt also nie versehentlich einen Schlüssel aus der Umgebung. Eine Variable, die gesetzt, aber leer ist, gilt als nicht gesetzt.

Was er vor dem Senden ablehnt

Diese Fälle lösen einen ArgumentError in der Zeile aus, die den falschen Wert enthielt, statt erst als verwirrender Fehlschlag bei Ihrem ersten Versand aufzutauchen. Die Meldung sagt, was falsch war und was Sie stattdessen übergeben sollten, und gibt nie Zugangsdaten wieder.

AbgelehntWarum
Gar keine ZugangsdatenWeder api_key: noch access_token: wurde übergeben, und bei init und create_client war auch keine der beiden Variablen gesetzt. Es gibt also nichts, womit sich der Client authentifizieren könnte. Wird beim Erzeugen des Clients ausgelöst.
Ein Schlüssel und ein Token zusammenJede Anfrage trägt genau einen Zugang, der Client kann also nicht erkennen, welchen Sie gemeint haben. Ein Schlüssel, der sowohl als erstes Argument als auch als api_key: übergeben wird, wird aus demselben Grund abgelehnt.
Ein Session-Cookie, ein Session-Token oder ein Schlüssel für einen anderen DienstNur oe_live_ und oe_test_ authentifizieren hier, und die API sagt das ebenfalls. Geprüft wird nur das Präfix, ein widerrufener Schlüssel scheitert daher erst bei der Anfrage, als OpenEmail::AuthenticationError.
Eine base_url:, die keine http- oder https-URL ist, oder eine, die einen Benutzernamen oder ein Passwort enthältEtwas anderes ist nicht erreichbar, und Zugangsdaten gehören in api_key: oder access_token:, nicht in die URL. Wird beim Erzeugen des Clients ausgelöst.
Zugangsdaten über einfaches http an einen Host, der nicht auf diesem Rechner liegtWird vom Aufruf ausgelöst, bevor etwas gesendet wird. Verwenden Sie eine https-Basis-URL.
Ein timeout:, das keine Anzahl von Sekunden oder negativ istÜbergeben Sie Sekunden oder 0 für kein Timeout. Wird beim Erzeugen des Clients ausgelöst.
Ein Header-Name, der kein gültiges Token ist, oder ein Zeilenumbruch in einem Header-WertGeprüft in headers:, user_agent: und idempotency_key:, weil ein Zeilenumbruch einen zweiten Header beginnen würde.
Eine leere oder nur aus Punkten bestehende id bei einer beliebigen MethodeWird beim Aufruf der Methode ausgelöst. Ein Pfadsegment aus Punkten wird von jedem URL-Parser entfernt, die Anfrage träfe also einen anderen Endpunkt. Eine id, die kein gültiges UTF-8 ist, wird ebenfalls abgelehnt.
Ein Request-Body, der kein Hash istÜbergeben Sie Keyword-Argumente oder einen einzelnen Hash. Alles, was auf to_hash antwortet, zählt als Hash.

Es gibt keine Option test_mode:, und es wird keine geben. Das Schlüsselschema ist Teil des Zugangs und kein bloßer Hinweis, der Modus ist also eine Eigenschaft des Schlüssels. client.mode liest das Präfix, "live" oder "test", und entscheidet nichts.

Ein Client, mehrere Schlüssel

Erzeugen Sie den Client einmal und teilen Sie ihn. Ein neuer Client pro Anfrage verwirft seine offenen Verbindungen ohne Nutzen, und nichts von seinem Zustand gehört zu einem bestimmten Aufrufer. Ein Client ist nach dem Erzeugen eingefroren und kann gefahrlos von vielen Threads gleichzeitig verwendet werden. Ein Puma- oder Sidekiq-Prozess braucht also nur einen, und nach einem Fork öffnet der Kindprozess eigene Verbindungen.

Für den Fall, der sonst einen Client pro Schlüssel erzwingen würde, etwa einen Job, der im Namen mehrerer Workspaces sendet, übergeben Sie api_key: beim Aufruf. Er ersetzt den Authorization-Header für diese Anfrage und hinterlässt nichts am Client.

per_call_key.rb
message = {from: "[email protected]", to: "[email protected]", subject: "Your invoice", text: "Attached."}workspace_key = ENV.fetch("OPENEMAIL_API_KEY") client.emails.send(message) client.emails.send(message, api_key: workspace_key) client.threads.list(folder: "inbox", api_key: workspace_key)client.webhooks.list(api_key: workspace_key)

Jede Methode außerhalb von temp_mail nimmt ihn als Keyword-Argument entgegen, neben den Filtern einer Liste, und die temp_mail-Methoden nehmen stattdessen inbox_token:. Er wird vor dem Senden der Anfrage nach derselben Regel geprüft, die der Client verwendet. Ein Tippfehler löst daher einen ArgumentError zum api_key dieses Aufrufs aus statt eines 401 zu Zugangsdaten, die Sie dann erst suchen müssen. Ein wiederholter Aufruf behält den Schlüssel, den er erhalten hat.

client.mode beschreibt den Schlüssel, mit dem der Client ERZEUGT wurde, und folgt keiner Überschreibung. Sobald ein Client mehrere Schlüssel bedient, gibt es keinen einzelnen Modus mehr zu melden, lesen Sie ihn also an dem Schlüssel ab, den Sie übergeben haben. client.inspect zeigt den Modus und die Basis-URL, nie den Schlüssel.

Endpunkte, die keine Methode kapselt

client.raw ist der Transport, über den jede Methode läuft. client.raw.request ruft einen Pfad auf, den noch keine Methode kapselt, mit den Zugangsdaten, der Basis-URL, dem Timeout und den Wiederholungsregeln des Clients, und gibt den geparsten Body so zurück, wie es eine Methode tut.

raw_request.rb
ping = client.raw.request("/ping") label = client.raw.request("/labels", method: :post, body: {name: "Invoices"}) p ping[:ok], label[:id]
KeywordWas es tut
method::get, sofern Sie nichts anderes angeben: :post, :put, :patch oder :delete.
query:Ein Hash mit Query-Parametern. nil und leere Werte werden weggelassen, ein Array oder ein Set wird mit Kommas verbunden, und ein Time wird als Zeitpunkt nach ISO 8601 gesendet.
body:Ein Hash, als JSON gesendet.
raw: und content_type:Bytes, die unverändert gesendet werden, als binärer String, IO oder Pathname, mit application/octet-stream, sofern Sie keinen Typ nennen.
accept: und binary:Ein anderes accept: als JSON gibt den Body als Text zurück, und binary: true gibt ihn als binären String zurück.
idempotent: und idempotency_key:idempotent: true hängt einen Idempotency-Key an, der erzeugt wird, sofern Sie keinen eigenen übergeben.
repeatable:Ob ein Fehlschlag wiederholt wird. Das gilt nur für ein GET, sofern Sie nicht repeatable: true übergeben.
api_key: und timeout:Derselbe Schlüssel pro Aufruf und ein Timeout in Sekunden nur für diesen Aufruf.

Der Pfad muss mit einem einzelnen / beginnen, und ein Pfad, dessen fertige URL den Origin der Basis-URL verlassen würde, löst einen ArgumentError aus, bevor etwas gesendet wird. So erreichen die Zugangsdaten nie einen anderen Host.

Wegwerf-Postfächer

OpenEmail.create_temp_mail erzeugt einen Client für Wegwerf-Posteingänge, der keinen API-Schlüssel trägt und keinen aus der Umgebung liest. Er legt Posteingänge anonym an, und jeder Lesezugriff sendet das Posteingangs-Token, das create zurückgegeben hat, oder das neuere, das extend zurückgegeben hat, entweder pro Aufruf als inbox_token: oder einmalig als OpenEmail.create_temp_mail(inbox_token:).

temp_mail.rb
temp_mail = OpenEmail.create_temp_mail inbox = temp_mail.createpage = temp_mail.list_messages(inbox[:id], inbox_token: inbox[:token]) p page.items.size, page.expires_at

create_temp_mail nimmt wie jeder Client base_url:, adapter:, max_retries:, timeout:, user_agent:, headers: und disable_update_notice: entgegen und liest OPENEMAIL_BASE_URL, wenn Sie keine Basis-URL übergeben.

OAuth-Zugriffstoken

Eine App, die jemand über OAuth verbunden hat, etwa ein Kommandozeilenwerkzeug oder ein Agent, hält ein Zugriffstoken statt eines API-Schlüssels. Übergeben Sie es als access_token:, entweder das Token selbst oder alles, was auf call antwortet und es zurückgibt, etwa ein Lambda oder eine Method. Das Callable wird einmal pro Aufruf aufgerufen, und die Wiederholungen dieses Aufrufs verwenden, was es zurückgab. Erneuern Sie das Token also darin, wenn es bald abläuft, dann muss der Client nie neu erzeugt werden.

access_token.rb
tokens = {current: "token-from-your-oauth-flow"} oauth_client = OpenEmail::Client.new(access_token: -> { tokens.fetch(:current) }) me = oauth_client.me.get puts me[:clientId], me[:expiresAt] if me[:object] == "oauth_token"
FallWas passiert
api_key: und access_token: zusammen oder keins von beidenDer Client löst beim Erzeugen einen ArgumentError aus. Fehlen beide, nennt die Meldung OPENEMAIL_API_KEY und OPENEMAIL_ACCESS_TOKEN.
Ein Wert, der kein Token istEin Token hat 1 bis 512 Zeichen und beginnt nicht mit oe_, die Prüfung, die OpenEmail.access_token? macht. Ein String, der sie nicht besteht, löst beim Erzeugen des Clients einen Fehler aus, und ein Callable, das so einen Wert zurückgibt, löst beim Aufruf einen ArgumentError aus, bevor irgendetwas gesendet wird.
OPENEMAIL_ACCESS_TOKENGelesen von init, create_client und dem gemeinsamen Client, wenn Sie keinen der beiden Zugänge übergeben und OPENEMAIL_API_KEY nicht gesetzt ist. Ein Schlüssel in der Umgebung hat also Vorrang.
Ein Callable, das einen Fehler auslöstDer Aufruf löst genau diesen Fehler unverändert aus, und es wird nichts gesendet.
Ein api_key: pro AufrufErsetzt das Token für diese eine Anfrage, und das Callable wird nicht aufgerufen.
client.modeUnter einem Token immer "live".
OpenEmail.create_temp_mailSendet keinen Zugang, egal was in der Umgebung steht.
me.get und me.pingFür ein Token antwortet get mit object gleich oauth_token, id und roleId nil, der clientId der verbundenen App und expiresAt, dem Zeitpunkt, an dem die Freigabe der Person für die App ausläuft. ping antwortet mit kind gleich oauth, keyId nil und der clientId. Prüfen Sie object oder kind, bevor Sie id oder keyId lesen.

Ein Token handelt für eine Person und liest ihre Mails so, wie sie es kann. Halten Sie es also wie einen Schlüssel auf einem Server.

Bestätigungscodes

Vor einer heiklen Änderung, etwa dem Löschen einer Domain oder dem Ändern eines Webhooks, verlangt die API von einem Zugriffstoken den Bestätigungscode, den die Web-App von der Person verlangen würde. Der Aufruf löst einen OpenEmail::PermissionError aus, einen 403, dessen step_up_required? true ist, und es wurde nichts geändert. Fordern Sie einen Code an, bestätigen Sie den, den die Person Ihnen gibt, und rufen Sie dann erneut auf. Ein API-Schlüssel wird nie gefragt.

step_up.rb
domain_id = "b3e1f0a4-6c2d-4e8a-9f17-2d5c8a0b4e6f" begin  client.domains.delete(domain_id)rescue OpenEmail::ApiError => error  raise unless error.step_up_required?   challenge = client.security.begin_step_up   if challenge[:method] == "email"    puts "Enter the code we emailed to #{challenge[:sentTo]}"  else    puts "Enter the code from your authenticator app, or a backup code"  end   client.security.verify_step_up(code: $stdin.gets.to_s.strip)  client.domains.delete(domain_id)end
MethodeWas es tut
security.step_up_statusOb die App gerade bestätigt ist (elevated, elevatedUntil), wie der nächste Code geprüft wird (method, email oder totp) und minutes, die Länge des Zeitfensters. Sie sendet nichts und meldet keine Pause.
security.begin_step_upEröffnet eine Abfrage. Bei email geht ein sechsstelliger Code an die Adresse, mit der sich die Person anmeldet, und sentTo zeigt sie maskiert. Bei totp liest sie einen aus ihrer Authenticator-App ab oder nimmt einen Wiederherstellungscode. Eine noch offene Abfrage mit verbleibenden Versuchen wird wiederverwendet, außer Sie übergeben resend: true, und eine gesperrte oder abgelaufene wird durch einen einfachen Aufruf ersetzt. Jede App darf pro Person 5 Abfragen pro Stunde und 20 in 24 Stunden eröffnen, und die nächste löst einen 429 step_up_throttled aus.
security.verify_step_up(code:)Prüft den Code und schaltet heikle Änderungen für diese App 60 Minuten lang frei, bis elevatedUntil, über REST und über die MCP-Tools, die dieselben Änderungen vornehmen. Nach 10 falschen Codes in 24 Stunden von dieser App oder 20 von allen Apps der Person zusammen lösen dieser Aufruf und begin_step_up einen 429 step_up_locked aus, mit einer Meldung, die sagt, wann die Bestätigung wieder möglich ist.

Der Client fragt nie selbst nach einem Code und wiederholt den Aufruf nicht von sich aus, und keine der drei Methoden wird automatisch wiederholt, weil ein erneuter Versuch nach einer verlorenen Antwort eine zweite E-Mail senden oder einen zweiten Versuch verbrauchen könnte. Sie brauchen keinen Scope, und ein API-Schlüssel bekommt bei jeder von ihnen einen 400 step_up_not_applicable. OpenEmail::STEP_UP_ERROR_CODES benennt jeden Grund, aus dem eine Bestätigung scheitern kann, und die Fehlerseite der API sagt, was jeweils zu tun ist.

Der Update-Hinweis

Wenn bei RubyGems eine neuere Version des Gems vorliegt, meldet der Client das einmal pro Prozess auf der Standardfehlerausgabe, als Zeile wie ℹ openemail 0.0.2 is available, you are on 0.0.1., gefolgt von der Seite des Gems. Die Prüfung läuft, wenn der erste Client erzeugt wird, in einem Hintergrund-Thread mit einem Timeout von zwei Sekunden und nur, wenn die Standardausgabe ein Terminal ist. Ist RubyGems nicht erreichbar, wird das ignoriert.

Die Prüfung läuft über den Adapter des Clients, ein Test-Adapter kann also eine Anfrage an RubyGems sehen, wenn die Tests in einem Terminal laufen. Erzeugen Sie Test-Clients mit disable_update_notice: true oder setzen Sie OPENEMAIL_DISABLE_UPDATE_NOTICE.

Proxys

Der Standardadapter findet seinen Proxy mit Rubys eigenem URI#find_proxy und folgt damit denselben Regeln wie der Rest der Standardbibliothek: https_proxy oder HTTPS_PROXY nennt den Proxy, und no_proxy oder NO_PROXY listet die Hosts, die direkt erreicht werden. Benutzername und Passwort in der Proxy-URL werden an den Proxy gesendet, und ein Server auf diesem Rechner wird nie über einen Proxy erreicht.

Verbindungen verwenden TLS 1.2 oder neuer und prüfen das Zertifikat des Servers. Ein Proxy, der TLS inspiziert, braucht daher eine Zertifizierungsstelle, der OpenSSL auf dem Rechner vertraut.

Testen ohne Netzwerk

adapter: ersetzt die HTTP-Schicht. Das ist alles, was auf call(request) antwortet, ein Lambda eingeschlossen, und ein OpenEmail::HttpResponse mit status, headers und body zurückgibt. Die Anfrage ist ein OpenEmail::HttpRequest mit method, url, headers, body und timeout, ein Test kann also genau prüfen, was hinausgegangen wäre.

fake_adapter.rb
requests = [] adapter = lambda do |request|  requests << request  OpenEmail::HttpResponse.new(    status: 200,    headers: {"content-type" => "application/json"},    body: JSON.generate({id: "msg_test", status: "sent", replayed: false})  )end test_client = OpenEmail::Client.new(api_key: "oe_test_fake", adapter:, max_retries: 0, disable_update_notice: true) sent = test_client.emails.send(from: "[email protected]", to: "[email protected]", subject: "Hi", text: "Hello") p sent[:status], requests.first.method, requests.first.url, requests.first.headers["Idempotency-Key"]p requests.first

Beim Ausgeben einer Anfrage erscheint ihr Authorization-Header als [redacted], ein Testprotokoll enthält also nie den Schlüssel.

  • Geben Sie einen Status außerhalb von 2xx mit dem Fehlerumschlag der API als Body zurück, etwa {"error": {"type": "validation_error", "code": "invalid_parameter", "message": "..."}}, um die passende Unterklasse von OpenEmail::ApiError zu erhalten.
  • Lösen Sie in call einen Timeout::Error aus oder einen Net::ReadTimeout, der einer ist, um einen OpenEmail::NetworkError zu erhalten, dessen timeout? true ist. Jeder andere StandardError, etwa Errno::ECONNREFUSED, wird zu einem NetworkError, dessen timeout? false ist.
  • NameError, TypeError und ArgumentError, die im Adapter ausgelöst werden, gelten als Fehler im Adapter selbst. Sie werden unverändert ausgelöst und nie wiederholt.

Erzeugen Sie einen Test-Client mit max_retries: 0, wenn Sie Fehlschläge skripten. Sonst wird ein wiederholbarer Status oder ein Netzwerkfehler bei einem Aufruf, der gefahrlos wiederholt werden kann, dreimal versucht, mit echten Wartezeiten dazwischen.