openemail 0.0.1
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.
- checksums.yaml +7 -0
- data/README.md +183 -0
- data/lib/openemail/api_paths.rb +249 -0
- data/lib/openemail/client.rb +69 -0
- data/lib/openemail/constants.rb +851 -0
- data/lib/openemail/credentials.rb +53 -0
- data/lib/openemail/decode.rb +34 -0
- data/lib/openemail/defaults.rb +111 -0
- data/lib/openemail/endpoint.rb +144 -0
- data/lib/openemail/errors.rb +121 -0
- data/lib/openemail/http.rb +172 -0
- data/lib/openemail/languages.rb +42 -0
- data/lib/openemail/pagination.rb +63 -0
- data/lib/openemail/protocol.rb +169 -0
- data/lib/openemail/raw_body.rb +83 -0
- data/lib/openemail/request_path.rb +50 -0
- data/lib/openemail/resource.rb +70 -0
- data/lib/openemail/resources/account.rb +64 -0
- data/lib/openemail/resources/addresses.rb +38 -0
- data/lib/openemail/resources/analytics.rb +17 -0
- data/lib/openemail/resources/app_host.rb +23 -0
- data/lib/openemail/resources/audiences.rb +90 -0
- data/lib/openemail/resources/billing.rb +64 -0
- data/lib/openemail/resources/branding.rb +24 -0
- data/lib/openemail/resources/broadcasts.rb +65 -0
- data/lib/openemail/resources/calendar.rb +59 -0
- data/lib/openemail/resources/chats.rb +31 -0
- data/lib/openemail/resources/contacts.rb +111 -0
- data/lib/openemail/resources/dns_connections.rb +19 -0
- data/lib/openemail/resources/domains.rb +153 -0
- data/lib/openemail/resources/drafts.rb +35 -0
- data/lib/openemail/resources/emails.rb +100 -0
- data/lib/openemail/resources/encryption.rb +19 -0
- data/lib/openemail/resources/exports.rb +27 -0
- data/lib/openemail/resources/files.rb +95 -0
- data/lib/openemail/resources/forms.rb +111 -0
- data/lib/openemail/resources/imports.rb +86 -0
- data/lib/openemail/resources/keys.rb +127 -0
- data/lib/openemail/resources/labels.rb +39 -0
- data/lib/openemail/resources/languages.rb +11 -0
- data/lib/openemail/resources/me.rb +19 -0
- data/lib/openemail/resources/members.rb +74 -0
- data/lib/openemail/resources/provider_imports.rb +40 -0
- data/lib/openemail/resources/roles.rb +39 -0
- data/lib/openemail/resources/rules.rb +57 -0
- data/lib/openemail/resources/security.rb +19 -0
- data/lib/openemail/resources/senders.rb +15 -0
- data/lib/openemail/resources/settings.rb +16 -0
- data/lib/openemail/resources/subscriptions.rb +30 -0
- data/lib/openemail/resources/support.rb +11 -0
- data/lib/openemail/resources/suppressions.rb +31 -0
- data/lib/openemail/resources/temp_mail.rb +67 -0
- data/lib/openemail/resources/templates.rb +151 -0
- data/lib/openemail/resources/threads.rb +104 -0
- data/lib/openemail/resources/tools.rb +19 -0
- data/lib/openemail/resources/tracking.rb +63 -0
- data/lib/openemail/resources/webhooks.rb +142 -0
- data/lib/openemail/resources/workspaces.rb +28 -0
- data/lib/openemail/results.rb +33 -0
- data/lib/openemail/transport.rb +272 -0
- data/lib/openemail/update_notice.rb +69 -0
- data/lib/openemail/version.rb +5 -0
- data/lib/openemail/webhook.rb +82 -0
- data/lib/openemail/wire.rb +95 -0
- data/lib/openemail.rb +125 -0
- metadata +109 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: b529e237ea6cc98204574ecf5b0b0b58fb7e774cd18ed07ac265ec243885fe1c
|
|
4
|
+
data.tar.gz: 26844441518ca76d25b0908248924119c0528f56bf874b919c6f4a8dd1942e2d
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: b6236ffe92657e77e6478042d728023a16826bbc194b70178d7cdb809815ef577bae64b62d1ada664760ad4f0a3771a04a2b993254a43bccceb9db541680c9bd
|
|
7
|
+
data.tar.gz: 871936c1946ea670dd8728a4651295114be58d11328307ba9bc298eb9b6c556793cb8112d932fe3a0958eb429f0c38721cd7072cc35fb8e2cf7d0f36fc033f47
|
data/README.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
<div align='center'>
|
|
2
|
+
<a href='https://openemail.uk'>
|
|
3
|
+
<img
|
|
4
|
+
src='https://openemail.uk/logo.svg'
|
|
5
|
+
alt='OpenEmail Logo'
|
|
6
|
+
width='180'
|
|
7
|
+
/>
|
|
8
|
+
</a>
|
|
9
|
+
|
|
10
|
+
<br />
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<p align='center'>
|
|
14
|
+
Email you can build on. Send mail, read the mailbox and automate a workspace from Ruby.
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
<p align='center'>
|
|
18
|
+
<a href='https://openemail.uk'><b>Website</b></a>
|
|
19
|
+
•
|
|
20
|
+
<a href='https://openemail.uk/docs/ruby'><b>Documentation</b></a>
|
|
21
|
+
•
|
|
22
|
+
<a href='https://openemail.uk/docs/ruby/reference/methods'><b>Every method</b></a>
|
|
23
|
+
•
|
|
24
|
+
<a href='https://openemail.uk/docs/api/reference'><b>API Reference</b></a>
|
|
25
|
+
</p>
|
|
26
|
+
|
|
27
|
+
<br />
|
|
28
|
+
|
|
29
|
+
## The Ruby gem
|
|
30
|
+
|
|
31
|
+
The official Ruby client for the OpenEmail API. It has one method for every method of the TypeScript SDK, under the same names in snake_case, and a parity check proves that each one sends the same request. It needs Ruby 3.2 or later and has no runtime dependencies: the HTTP client is Net::HTTP from the standard library, with a pool of kept-alive connections that one client shares safely across threads and that is rebuilt after a fork.
|
|
32
|
+
|
|
33
|
+
It carries a workspace API key or an OAuth access token, so it belongs on a server, in a job or in a tool that runs on your own machine.
|
|
34
|
+
|
|
35
|
+
### Installing
|
|
36
|
+
```bash
|
|
37
|
+
bundle add openemail
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Or `gem install openemail` without Bundler.
|
|
41
|
+
|
|
42
|
+
### Using
|
|
43
|
+
```ruby
|
|
44
|
+
require "openemail"
|
|
45
|
+
|
|
46
|
+
client = OpenEmail::Client.new(api_key: ENV.fetch("OPENEMAIL_API_KEY"))
|
|
47
|
+
|
|
48
|
+
sent = client.emails.send(
|
|
49
|
+
from: "Acme Billing <billing@acme.com>",
|
|
50
|
+
to: "ada@example.com",
|
|
51
|
+
subject: "Your September invoice",
|
|
52
|
+
html: "<p>Your invoice is attached.</p>",
|
|
53
|
+
attachments: [{filename: "invoice.pdf", content: File.binread("invoice.pdf"), contentType: "application/pdf"}]
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
puts sent[:id], sent[:status]
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Create a key in OpenEmail under Settings, API keys. It is shown once, and it belongs in an environment variable or your credentials store rather than in code.
|
|
60
|
+
|
|
61
|
+
A request body goes in as keyword arguments or as one Hash, and its keys keep the API's names, so `replyTo:`, `scheduledAt:` and `contentType:` stay camelCase. Options of the call itself are snake_case: `idempotency_key:`, `api_key:`, `limit:`, `cursor:`. What comes back is the parsed JSON as a Hash with Symbol keys, read with `sent[:id]`.
|
|
62
|
+
|
|
63
|
+
Or skip building a client. `OpenEmail.emails`, `OpenEmail.threads` and every other namespace use a shared client built from `OPENEMAIL_API_KEY` the first time one is touched:
|
|
64
|
+
|
|
65
|
+
```ruby
|
|
66
|
+
OpenEmail.emails.send(from: "hello@acme.com", to: "ada@example.com", subject: "Welcome", text: "Glad you are here.")
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Every send carries an idempotency key, generated once per call and reused by its retries, so a retried request replays the original message rather than sending a second one. Pass your own with `idempotency_key:` to make that hold across processes and restarts.
|
|
70
|
+
|
|
71
|
+
### Reading the mailbox
|
|
72
|
+
```ruby
|
|
73
|
+
page = client.threads.list(folder: "inbox", limit: 25)
|
|
74
|
+
page.items.each { |thread| puts thread[:subject] }
|
|
75
|
+
|
|
76
|
+
client.threads.iterate(folder: "inbox", query: "invoice") do |thread|
|
|
77
|
+
full = client.threads.get(thread[:id])
|
|
78
|
+
puts full[:messageCount], full[:hasUnread]
|
|
79
|
+
end
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Every paginated resource has `list` for one page (an `OpenEmail::Page` with `items`, `has_more?` and `next_cursor`), `list_all` for every page at once as an Array, and `iterate`, which yields each item to a block, or without one returns an Enumerator that fetches the next page only when it gets there, so `first(10)` stops early. `addresses.list_all` is the exception and returns the whole address book.
|
|
83
|
+
|
|
84
|
+
### Errors
|
|
85
|
+
```ruby
|
|
86
|
+
template = "order-shipped"
|
|
87
|
+
|
|
88
|
+
begin
|
|
89
|
+
client.templates.send(template, from: "dispatch@acme.com", to: "ada@example.com", props: {orderId: "AC-4192"})
|
|
90
|
+
rescue OpenEmail::ValidationError => error
|
|
91
|
+
warn [error.code, error.param, error.request_id].join(" ")
|
|
92
|
+
raise
|
|
93
|
+
end
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
An API refusal raises an `OpenEmail::ApiError`, or the subclass for its type: `AuthenticationError`, `PermissionError`, `NotFoundError`, `ConflictError`, `ValidationError`, `RateLimitError` or `InvalidRequestError`. Each carries `status`, `type`, `code`, `param`, `request_id` and `body`, plus `validation?`, `not_found?`, `rate_limited?` and friends to branch on. No response at all raises `OpenEmail::NetworkError`, with `timeout?` when the deadline passed. A mistake in the call itself, such as a malformed key or an empty id, raises `ArgumentError` before anything is sent.
|
|
97
|
+
|
|
98
|
+
### Webhooks
|
|
99
|
+
```ruby
|
|
100
|
+
class OpenEmailWebhooksController < ActionController::API
|
|
101
|
+
def create
|
|
102
|
+
event = OpenEmail.verify_webhook_signature(
|
|
103
|
+
payload: request.raw_post,
|
|
104
|
+
headers: request.headers,
|
|
105
|
+
secret: Rails.application.credentials.openemail_webhook_secret
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
Rails.logger.info("#{event[:type]} #{event[:data]}")
|
|
109
|
+
head :no_content
|
|
110
|
+
rescue OpenEmail::WebhookSignatureError
|
|
111
|
+
head :bad_request
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
It checks the HMAC in constant time and rejects a delivery more than five minutes old, then returns the parsed event. Pass the raw body: a parsed or re-encoded body no longer matches its signature. The headers can be a Hash in any case, a Rack env or Rails' `request.headers`.
|
|
117
|
+
|
|
118
|
+
### Disposable inboxes
|
|
119
|
+
```ruby
|
|
120
|
+
temp_mail = OpenEmail.create_temp_mail
|
|
121
|
+
|
|
122
|
+
inbox = temp_mail.create(ttlMinutes: 60)
|
|
123
|
+
|
|
124
|
+
page = temp_mail.list_messages(inbox[:id], inbox_token: inbox[:token])
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
`create` needs no credential and is the only call that returns the inbox token, so keep it.
|
|
128
|
+
|
|
129
|
+
### OAuth access tokens
|
|
130
|
+
An app a person connected to OpenEmail with OAuth, such as a command line tool or an agent, holds an access token rather than an API key. Pass it as `access_token:`, either the token itself or anything that responds to `call` and returns it:
|
|
131
|
+
|
|
132
|
+
```ruby
|
|
133
|
+
client = OpenEmail::Client.new(access_token: -> { session.fresh_access_token })
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
The callable runs before every request, so renew the token there when it is close to expiring and the client never has to be rebuilt. Pass `api_key:` or `access_token:`, not both. `OpenEmail.create_client` reads `OPENEMAIL_ACCESS_TOKEN` when you pass neither and `OPENEMAIL_API_KEY` is not set.
|
|
137
|
+
|
|
138
|
+
A token acts for a person, so before a sensitive change, such as deleting a domain or changing a webhook, it is asked for the same verification code the web app asks for. The request raises with `step_up_required?`. Ask for a code, check it, then replay the request:
|
|
139
|
+
|
|
140
|
+
```ruby
|
|
141
|
+
begin
|
|
142
|
+
client.domains.delete(domain_id)
|
|
143
|
+
rescue OpenEmail::ApiError => error
|
|
144
|
+
raise unless error.step_up_required?
|
|
145
|
+
|
|
146
|
+
challenge = client.security.begin_step_up
|
|
147
|
+
code = ask(challenge[:method] == "email" ? "Enter the code we emailed to #{challenge[:sentTo]}" : "Enter the code from your authenticator app")
|
|
148
|
+
|
|
149
|
+
client.security.verify_step_up(code:)
|
|
150
|
+
client.domains.delete(domain_id)
|
|
151
|
+
end
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
API keys are never asked for a code.
|
|
155
|
+
|
|
156
|
+
### Configuring
|
|
157
|
+
```ruby
|
|
158
|
+
client = OpenEmail::Client.new(
|
|
159
|
+
api_key: ENV.fetch("OPENEMAIL_API_KEY"),
|
|
160
|
+
base_url: "https://api.openemail.uk",
|
|
161
|
+
timeout: 30,
|
|
162
|
+
max_retries: 2,
|
|
163
|
+
headers: {"X-Team" => "billing"}
|
|
164
|
+
)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
`OpenEmail.create_client(...)` takes the same options and reads what you leave out from the environment: `OPENEMAIL_API_KEY`, then `OPENEMAIL_ACCESS_TOKEN`, and `OPENEMAIL_BASE_URL`, where a bare host such as `localhost:2222` gets its scheme added. `OpenEmail.init(...)` does the same for the shared client.
|
|
168
|
+
|
|
169
|
+
Use an `https:` origin: the client refuses to send an API key, an access token or an inbox token over plain `http:` unless the server is on this machine, at `localhost`, a `127.x.x.x` address or `::1`. A `base_url` on `0.0.0.0` raises when the client is built, since that is the address a server listens on: use `127.0.0.1` with the same port. `timeout:` is in seconds and bounds a whole attempt, 0 turns it off, and uploads wait at least ten minutes. Reads, sends and every write that is safe to repeat are retried on 408, 500, 502, 503 and 504 with backoff, and on a 429 only when it carries a `Retry-After` of a minute or less. Any other write is never retried. Every method takes `api_key:` to act with another key for one call, so one process can serve several workspaces with one client, and the `temp_mail` methods take `inbox_token:` instead. `HTTPS_PROXY` and `NO_PROXY` are honoured.
|
|
170
|
+
|
|
171
|
+
An endpoint no method wraps yet is one `client.raw.request` away, with the client's credential, base URL, timeout and retry policy applied:
|
|
172
|
+
|
|
173
|
+
```ruby
|
|
174
|
+
client.raw.request("/something-new", method: :post, body: {name: "Invoices"})
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
The path must begin with a single `/`, and a path whose finished URL leaves the base URL's origin raises before a request is sent, so the credential never reaches another host.
|
|
178
|
+
|
|
179
|
+
`adapter:` swaps the HTTP layer for anything that responds to `call(request)` and returns an `OpenEmail::HttpResponse`, which is how a test drives the client without a network.
|
|
180
|
+
|
|
181
|
+
When a newer version is on RubyGems the client says so once on a TTY. `OPENEMAIL_DISABLE_UPDATE_NOTICE=1` or `disable_update_notice: true` turns that off.
|
|
182
|
+
|
|
183
|
+
Everything else, from templates, rules, tracking, calendar, contacts, audiences and broadcasts to roles, members, settings, mailbox imports and provider imports, plus the full reference for every method, lives in the [documentation](https://openemail.uk/docs/ruby). What changed in each release is in the [changelog](https://openemail.uk/docs/ruby/changelog).
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OpenEmail
|
|
4
|
+
module ApiPaths
|
|
5
|
+
ACCOUNT_CONNECTED_APP = "/account/connected-apps/:clientId"
|
|
6
|
+
ACCOUNT_CONNECTED_APPS = "/account/connected-apps"
|
|
7
|
+
ACCOUNT_INVITATIONS = "/account/invitations"
|
|
8
|
+
ACCOUNT_INVITATION_ACCEPT = "/account/invitations/:invitationId/accept"
|
|
9
|
+
ACCOUNT_INVITATION_DECLINE = "/account/invitations/:invitationId/decline"
|
|
10
|
+
ACCOUNT_NOTIFICATIONS = "/account/notifications"
|
|
11
|
+
ACCOUNT_NOTIFICATION_EMAIL = "/account/notifications/email/:category"
|
|
12
|
+
ACCOUNT_NOTIFICATION_PUSH = "/account/notifications/push/:workspaceId"
|
|
13
|
+
ACCOUNT_PHOTO = "/account/photo"
|
|
14
|
+
ACCOUNT_USERNAME = "/account/username"
|
|
15
|
+
ACCOUNT_USERNAME_AVAILABILITY = "/account/username/availability"
|
|
16
|
+
ADDRESSES = "/addresses"
|
|
17
|
+
ANALYTICS_MAILBOX = "/analytics/mailbox"
|
|
18
|
+
ANALYTICS_SENDING = "/analytics/sending"
|
|
19
|
+
APP_HOST = "/app-host"
|
|
20
|
+
APP_HOST_VERIFY = "/app-host/verify"
|
|
21
|
+
AUDIENCE = "/audiences/:id"
|
|
22
|
+
AUDIENCES = "/audiences"
|
|
23
|
+
AUDIENCES_GROWTH = "/audiences/growth"
|
|
24
|
+
AUDIENCE_CONTACT = "/audiences/:id/contacts/:email"
|
|
25
|
+
AUDIENCE_CONTACTS = "/audiences/:id/contacts"
|
|
26
|
+
AUDIENCE_CONTACTS_BATCH = "/audiences/:id/contacts/batch"
|
|
27
|
+
AUDIENCE_CONTACTS_BATCH_REMOVE = "/audiences/:id/contacts/batch-remove"
|
|
28
|
+
AUDIENCE_EMPTY = "/audiences/:id/empty"
|
|
29
|
+
AUDIENCE_IMPORT = "/audiences/:id/import"
|
|
30
|
+
BILLING = "/billing"
|
|
31
|
+
BILLING_ALERTS = "/billing/alerts"
|
|
32
|
+
BILLING_CHECKOUT = "/billing/checkout"
|
|
33
|
+
BILLING_COUNTRIES = "/billing/countries"
|
|
34
|
+
BILLING_INVOICE = "/billing/invoices/:orderId"
|
|
35
|
+
BILLING_INVOICES = "/billing/invoices"
|
|
36
|
+
BILLING_INVOICE_DETAILS = "/billing/invoices/:orderId/details"
|
|
37
|
+
BILLING_PAY_AS_YOU_GO = "/billing/pay-as-you-go"
|
|
38
|
+
BILLING_PAY_AS_YOU_GO_CONFIRM = "/billing/pay-as-you-go/confirm"
|
|
39
|
+
BILLING_PAY_AS_YOU_GO_LIMIT = "/billing/pay-as-you-go/limit"
|
|
40
|
+
BILLING_PLANS = "/billing/plans"
|
|
41
|
+
BILLING_PORTAL = "/billing/portal"
|
|
42
|
+
BILLING_USAGE = "/billing/usage"
|
|
43
|
+
BRANDING = "/branding"
|
|
44
|
+
BRANDING_IMAGE = "/branding/images/:variant"
|
|
45
|
+
BROADCAST = "/broadcasts/:id"
|
|
46
|
+
BROADCASTS = "/broadcasts"
|
|
47
|
+
BROADCASTS_ANALYTICS = "/broadcasts/analytics"
|
|
48
|
+
BROADCASTS_PREVIEW = "/broadcasts/preview"
|
|
49
|
+
BROADCAST_CANCEL = "/broadcasts/:id/cancel"
|
|
50
|
+
BROADCAST_RECIPIENT = "/broadcasts/:id/recipients/:emailId"
|
|
51
|
+
BROADCAST_RECIPIENTS = "/broadcasts/:id/recipients"
|
|
52
|
+
BROADCAST_STATS = "/broadcasts/:id/stats"
|
|
53
|
+
CALENDAR_EVENT = "/calendar/events/:id"
|
|
54
|
+
CALENDAR_EVENTS = "/calendar/events"
|
|
55
|
+
CALENDAR_EVENT_CANCEL = "/calendar/events/:id/cancel"
|
|
56
|
+
CALENDAR_EVENT_ICS = "/calendar/events/:id/ics"
|
|
57
|
+
CALENDAR_EVENT_RESPOND = "/calendar/events/:id/respond"
|
|
58
|
+
CHAT = "/chats/:id"
|
|
59
|
+
CHATS = "/chats"
|
|
60
|
+
CONTACT = "/contacts/:email"
|
|
61
|
+
CONTACTS = "/contacts"
|
|
62
|
+
CONTACTS_BATCH_DELETE = "/contacts/batch-delete"
|
|
63
|
+
CONTACTS_PEOPLE = "/contacts/people"
|
|
64
|
+
CONTACT_ACTIVITY = "/contacts/:email/activity"
|
|
65
|
+
CONTACT_AUDIENCES = "/contacts/:email/audiences"
|
|
66
|
+
CONTACT_BLOCK = "/contacts/:email/block"
|
|
67
|
+
CONTACT_PHOTO = "/contacts/:email/photo"
|
|
68
|
+
CONTACT_THREADS = "/contacts/:email/threads"
|
|
69
|
+
DNS_CONNECTION = "/dns-connections/:id"
|
|
70
|
+
DNS_CONNECTIONS = "/dns-connections"
|
|
71
|
+
DOMAIN = "/domains/:id"
|
|
72
|
+
DOMAINS = "/domains"
|
|
73
|
+
DOMAIN_ADDRESS = "/domains/:id/addresses/:addressId"
|
|
74
|
+
DOMAIN_ADDRESSES = "/domains/:id/addresses"
|
|
75
|
+
DOMAIN_ADDRESS_FORWARD = "/domains/:id/addresses/:addressId/forwards/:forwardId"
|
|
76
|
+
DOMAIN_ADDRESS_FORWARDS = "/domains/:id/addresses/:addressId/forwards"
|
|
77
|
+
DOMAIN_ADDRESS_FORWARD_RESEND = "/domains/:id/addresses/:addressId/forwards/:forwardId/resend"
|
|
78
|
+
DOMAIN_ADDRESS_LOGIN = "/domains/:id/addresses/:addressId/login"
|
|
79
|
+
DOMAIN_ADDRESS_MEMBERS = "/domains/:id/addresses/:addressId/members"
|
|
80
|
+
DOMAIN_ADDRESS_PHOTO = "/domains/:id/addresses/:addressId/photo"
|
|
81
|
+
DOMAIN_DNS = "/domains/:id/dns"
|
|
82
|
+
DOMAIN_DNS_SYNC = "/domains/:id/dns/sync"
|
|
83
|
+
DOMAIN_LOGO = "/domains/:id/logo"
|
|
84
|
+
DOMAIN_LOGO_CERTIFICATE = "/domains/:id/logo/certificate"
|
|
85
|
+
DOMAIN_VERIFY = "/domains/:id/verify"
|
|
86
|
+
DRAFT = "/drafts/:id"
|
|
87
|
+
DRAFTS = "/drafts"
|
|
88
|
+
EMAIL = "/emails/:id"
|
|
89
|
+
EMAILS = "/emails"
|
|
90
|
+
EMAILS_BATCH = "/emails/batch"
|
|
91
|
+
EMAILS_CHECK = "/emails/check"
|
|
92
|
+
EMAILS_COMPOSE = "/emails/compose"
|
|
93
|
+
EMAILS_REWRITE = "/emails/rewrite"
|
|
94
|
+
EMAILS_SUBJECT = "/emails/subject"
|
|
95
|
+
EMAILS_TRANSLATE = "/emails/translate"
|
|
96
|
+
EMAIL_CANCEL = "/emails/:id/cancel"
|
|
97
|
+
EMAIL_EVENTS = "/emails/:id/events"
|
|
98
|
+
EMAIL_TRACKING = "/emails/:id/tracking"
|
|
99
|
+
ENCRYPTION_KEYS = "/encryption/keys"
|
|
100
|
+
ENCRYPTION_KEYS_LOOKUP = "/encryption/keys/lookup"
|
|
101
|
+
FILE = "/files/:id"
|
|
102
|
+
FILES = "/files"
|
|
103
|
+
FILES_BATCH_DELETE = "/files/batch-delete"
|
|
104
|
+
FILES_STATS = "/files/stats"
|
|
105
|
+
FILE_CONTENT = "/files/:id/content"
|
|
106
|
+
FILE_LINK = "/files/:id/links/:linkId"
|
|
107
|
+
FILE_LINKS = "/files/:id/links"
|
|
108
|
+
FORM = "/forms/:id"
|
|
109
|
+
FORMS = "/forms"
|
|
110
|
+
FORMS_DESIGN = "/forms/design"
|
|
111
|
+
FORM_ANALYTICS = "/forms/:id/analytics"
|
|
112
|
+
FORM_DUPLICATE = "/forms/:id/duplicate"
|
|
113
|
+
FORM_PAUSE = "/forms/:id/pause"
|
|
114
|
+
FORM_PUBLISH = "/forms/:id/publish"
|
|
115
|
+
FORM_REDESIGN = "/forms/:id/redesign"
|
|
116
|
+
FORM_RESUME = "/forms/:id/resume"
|
|
117
|
+
FORM_STARTER = "/forms/starters/:slug"
|
|
118
|
+
FORM_STARTERS = "/forms/starters"
|
|
119
|
+
FORM_SUBMISSION = "/forms/:id/submissions/:submissionId"
|
|
120
|
+
FORM_SUBMISSIONS = "/forms/:id/submissions"
|
|
121
|
+
FORM_SUBMISSIONS_BATCH_REMOVE = "/forms/:id/submissions/batch-remove"
|
|
122
|
+
FORM_SUBMISSION_APPROVE = "/forms/:id/submissions/:submissionId/approve"
|
|
123
|
+
FORM_SUBMISSION_RESEND = "/forms/:id/submissions/:submissionId/resend"
|
|
124
|
+
IMPORT = "/imports/:id"
|
|
125
|
+
IMPORTS = "/imports"
|
|
126
|
+
IMPORT_CANCEL = "/imports/:id/cancel"
|
|
127
|
+
IMPORT_FAILURES = "/imports/:id/failures"
|
|
128
|
+
IMPORT_FILE_CHUNK = "/imports/:id/files/:file/chunks/:chunk"
|
|
129
|
+
IMPORT_START = "/imports/:id/start"
|
|
130
|
+
IMPORT_UPLOAD = "/imports/:id/upload"
|
|
131
|
+
KEY = "/keys/:id"
|
|
132
|
+
KEYS = "/keys"
|
|
133
|
+
KEYS_ACTIVITY = "/keys/activity"
|
|
134
|
+
KEYS_REQUESTS = "/keys/requests"
|
|
135
|
+
KEYS_STATS = "/keys/stats"
|
|
136
|
+
KEY_ACTIVITY = "/keys/:id/activity"
|
|
137
|
+
KEY_REQUESTS = "/keys/:id/requests"
|
|
138
|
+
KEY_REVOKE = "/keys/:id/revoke"
|
|
139
|
+
KEY_ROTATE = "/keys/:id/rotate"
|
|
140
|
+
KEY_SELF = "/keys/self"
|
|
141
|
+
KEY_SELF_ROTATE = "/keys/self/rotate"
|
|
142
|
+
LABEL = "/labels/:id"
|
|
143
|
+
LABELS = "/labels"
|
|
144
|
+
LABEL_COLORS = "/labels/colors"
|
|
145
|
+
LANGUAGES = "/languages"
|
|
146
|
+
MAILBOX_EXPORT = "/exports/:id"
|
|
147
|
+
MAILBOX_EXPORTS = "/exports"
|
|
148
|
+
MAILBOX_EXPORTS_PREVIEW = "/exports/preview"
|
|
149
|
+
MAILBOX_EXPORT_CONTENT = "/exports/:id/content"
|
|
150
|
+
MEMBER = "/members/:userId"
|
|
151
|
+
MEMBERS = "/members"
|
|
152
|
+
MEMBER_ADDRESS = "/members/:userId/addresses/:addressId"
|
|
153
|
+
MEMBER_ADDRESSES = "/members/:userId/addresses"
|
|
154
|
+
MEMBER_DOMAIN = "/members/:userId/domains/:domainId"
|
|
155
|
+
MEMBER_DOMAINS = "/members/:userId/domains"
|
|
156
|
+
MEMBER_INVITATION = "/members/invitations/:invitationId"
|
|
157
|
+
MEMBER_INVITATIONS = "/members/invitations"
|
|
158
|
+
MEMBER_INVITATION_RESEND = "/members/invitations/:invitationId/resend"
|
|
159
|
+
PING = "/ping"
|
|
160
|
+
PROVIDER_IMPORT = "/provider-imports/:id"
|
|
161
|
+
PROVIDER_IMPORTS = "/provider-imports"
|
|
162
|
+
PROVIDER_IMPORTS_INSPECT = "/provider-imports/inspect"
|
|
163
|
+
PROVIDER_IMPORT_CANCEL = "/provider-imports/:id/cancel"
|
|
164
|
+
ROLE = "/roles/:id"
|
|
165
|
+
ROLES = "/roles"
|
|
166
|
+
ROLE_PERMISSIONS = "/roles/permissions"
|
|
167
|
+
RULE = "/rules/:id"
|
|
168
|
+
RULES = "/rules"
|
|
169
|
+
RULES_REORDER = "/rules/reorder"
|
|
170
|
+
RULE_RUNS = "/rules/runs"
|
|
171
|
+
RULE_TEST = "/rules/:id/test"
|
|
172
|
+
SECURITY_STEP_UP = "/security/step-up"
|
|
173
|
+
SECURITY_STEP_UP_VERIFY = "/security/step-up/verify"
|
|
174
|
+
SENDER = "/senders/:email"
|
|
175
|
+
SENDER_RESEARCH = "/senders/:email/research"
|
|
176
|
+
SETTINGS = "/settings"
|
|
177
|
+
SUBSCRIBE_FORM = "/subscribe/:formId"
|
|
178
|
+
SUBSCRIPTIONS = "/subscriptions"
|
|
179
|
+
SUBSCRIPTION_DOMAINS = "/subscriptions/domains"
|
|
180
|
+
SUBSCRIPTION_DOMAIN_UNSUBSCRIBE = "/subscriptions/domains/:domain/unsubscribe"
|
|
181
|
+
SUBSCRIPTION_MOVE = "/subscriptions/:id/move"
|
|
182
|
+
SUBSCRIPTION_UNSUBSCRIBE = "/subscriptions/:id/unsubscribe"
|
|
183
|
+
SUPPORT = "/support"
|
|
184
|
+
SUPPRESSION = "/suppressions/:id"
|
|
185
|
+
SUPPRESSIONS = "/suppressions"
|
|
186
|
+
TEMPLATE = "/templates/:id"
|
|
187
|
+
TEMPLATES = "/templates"
|
|
188
|
+
TEMPLATES_DESIGN = "/templates/design"
|
|
189
|
+
TEMPLATE_ANALYTICS = "/templates/:id/analytics"
|
|
190
|
+
TEMPLATE_CONTENT = "/templates/:id/content"
|
|
191
|
+
TEMPLATE_DUPLICATE = "/templates/:id/duplicate"
|
|
192
|
+
TEMPLATE_FONTS = "/templates/fonts"
|
|
193
|
+
TEMPLATE_IMAGES = "/templates/images"
|
|
194
|
+
TEMPLATE_PREVIEW = "/templates/:id/preview"
|
|
195
|
+
TEMPLATE_REDESIGN = "/templates/:id/redesign"
|
|
196
|
+
TEMPLATE_RENDER = "/templates/render"
|
|
197
|
+
TEMPLATE_SEND = "/templates/:id/send"
|
|
198
|
+
TEMPLATE_SENDS = "/templates/:id/sends"
|
|
199
|
+
TEMPLATE_STARTER = "/templates/starters/:slug"
|
|
200
|
+
TEMPLATE_STARTERS = "/templates/starters"
|
|
201
|
+
TEMPLATE_VERSION = "/templates/:id/versions/:version"
|
|
202
|
+
TEMPLATE_VERSIONS = "/templates/:id/versions"
|
|
203
|
+
TEMPLATE_VERSION_RESTORE = "/templates/:id/versions/:version/restore"
|
|
204
|
+
TEMP_MAIL_DOMAINS = "/temp-mail/domains"
|
|
205
|
+
TEMP_MAIL_INBOX = "/temp-mail/inboxes/:id"
|
|
206
|
+
TEMP_MAIL_INBOXES = "/temp-mail/inboxes"
|
|
207
|
+
TEMP_MAIL_INBOX_EXTEND = "/temp-mail/inboxes/:id/extend"
|
|
208
|
+
TEMP_MAIL_MESSAGE = "/temp-mail/inboxes/:id/messages/:messageId"
|
|
209
|
+
TEMP_MAIL_MESSAGES = "/temp-mail/inboxes/:id/messages"
|
|
210
|
+
TEMP_MAIL_MESSAGE_ATTACHMENTS = "/temp-mail/inboxes/:id/messages/:messageId/attachments"
|
|
211
|
+
THREAD = "/threads/:id"
|
|
212
|
+
THREADS = "/threads"
|
|
213
|
+
THREADS_COUNTS = "/threads/counts"
|
|
214
|
+
THREAD_EVENT = "/threads/:id/event"
|
|
215
|
+
THREAD_MESSAGE_ATTACHMENTS = "/threads/:id/messages/:messageId/attachments"
|
|
216
|
+
THREAD_NOTE = "/threads/:id/notes/:noteId"
|
|
217
|
+
THREAD_NOTES = "/threads/:id/notes"
|
|
218
|
+
THREAD_NOTES_REORDER = "/threads/:id/notes/reorder"
|
|
219
|
+
THREAD_RESTORE = "/threads/:id/restore"
|
|
220
|
+
THREAD_SNOOZE = "/threads/:id/snooze"
|
|
221
|
+
THREAD_SUMMARY = "/threads/:id/summary"
|
|
222
|
+
THREAD_TRASH = "/threads/:id/trash"
|
|
223
|
+
THREAD_UNSNOOZE = "/threads/:id/unsnooze"
|
|
224
|
+
THREAD_UNSUBSCRIBE = "/threads/:id/unsubscribe"
|
|
225
|
+
TOOLS_BIMI = "/tools/bimi"
|
|
226
|
+
TOOLS_DELIVERABILITY = "/tools/deliverability"
|
|
227
|
+
TOOLS_DMARC = "/tools/dmarc"
|
|
228
|
+
TRACKED = "/tracking/:id"
|
|
229
|
+
TRACKED_CLICKS = "/tracking/:id/clicks"
|
|
230
|
+
TRACKED_OPENS = "/tracking/:id/opens"
|
|
231
|
+
TRACKING = "/tracking"
|
|
232
|
+
TRACKING_STATS = "/tracking/stats"
|
|
233
|
+
WEBHOOK = "/webhooks/:id"
|
|
234
|
+
WEBHOOKS = "/webhooks"
|
|
235
|
+
WEBHOOKS_ACTIVITY = "/webhooks/activity"
|
|
236
|
+
WEBHOOKS_DELIVERIES = "/webhooks/deliveries"
|
|
237
|
+
WEBHOOKS_EVENTS = "/webhooks/events"
|
|
238
|
+
WEBHOOKS_STATS = "/webhooks/stats"
|
|
239
|
+
WEBHOOK_ACTIVITY = "/webhooks/:id/activity"
|
|
240
|
+
WEBHOOK_DELIVERIES = "/webhooks/:id/deliveries"
|
|
241
|
+
WEBHOOK_DELIVERY = "/webhooks/:id/deliveries/:deliveryId"
|
|
242
|
+
WEBHOOK_DELIVERY_REPLAY = "/webhooks/:id/deliveries/:deliveryId/replay"
|
|
243
|
+
WEBHOOK_ROTATE_SECRET = "/webhooks/:id/rotate-secret"
|
|
244
|
+
WEBHOOK_TEST = "/webhooks/:id/test"
|
|
245
|
+
WORKSPACE = "/workspaces/:id"
|
|
246
|
+
WORKSPACES = "/workspaces"
|
|
247
|
+
WORKSPACES_ACTIVE = "/workspaces/active"
|
|
248
|
+
end
|
|
249
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OpenEmail
|
|
4
|
+
class Client
|
|
5
|
+
NAMESPACES = {
|
|
6
|
+
me: Resources::Me,
|
|
7
|
+
security: Resources::Security,
|
|
8
|
+
keys: Resources::Keys,
|
|
9
|
+
addresses: Resources::Addresses,
|
|
10
|
+
languages: Resources::Languages,
|
|
11
|
+
emails: Resources::Emails,
|
|
12
|
+
templates: Resources::Templates,
|
|
13
|
+
tracking: Resources::Tracking,
|
|
14
|
+
threads: Resources::Threads,
|
|
15
|
+
drafts: Resources::Drafts,
|
|
16
|
+
labels: Resources::Labels,
|
|
17
|
+
contacts: Resources::Contacts,
|
|
18
|
+
audiences: Resources::Audiences,
|
|
19
|
+
billing: Resources::Billing,
|
|
20
|
+
forms: Resources::Forms,
|
|
21
|
+
broadcasts: Resources::Broadcasts,
|
|
22
|
+
domains: Resources::Domains,
|
|
23
|
+
app_host: Resources::AppHost,
|
|
24
|
+
branding: Resources::Branding,
|
|
25
|
+
rules: Resources::Rules,
|
|
26
|
+
webhooks: Resources::Webhooks,
|
|
27
|
+
imports: Resources::Imports,
|
|
28
|
+
provider_imports: Resources::ProviderImports,
|
|
29
|
+
calendar: Resources::Calendar,
|
|
30
|
+
settings: Resources::Settings,
|
|
31
|
+
roles: Resources::Roles,
|
|
32
|
+
members: Resources::Members,
|
|
33
|
+
suppressions: Resources::Suppressions,
|
|
34
|
+
files: Resources::Files,
|
|
35
|
+
temp_mail: Resources::TempMail,
|
|
36
|
+
exports: Resources::Exports,
|
|
37
|
+
chats: Resources::Chats,
|
|
38
|
+
encryption: Resources::Encryption,
|
|
39
|
+
support: Resources::Support,
|
|
40
|
+
tools: Resources::Tools,
|
|
41
|
+
senders: Resources::Senders,
|
|
42
|
+
analytics: Resources::Analytics,
|
|
43
|
+
subscriptions: Resources::Subscriptions,
|
|
44
|
+
dns_connections: Resources::DnsConnections,
|
|
45
|
+
workspaces: Resources::Workspaces,
|
|
46
|
+
account: Resources::Account
|
|
47
|
+
}.freeze
|
|
48
|
+
|
|
49
|
+
attr_reader :mode, :raw, *NAMESPACES.keys
|
|
50
|
+
|
|
51
|
+
def initialize(key = nil, api_key: nil, access_token: nil, base_url: nil, adapter: nil, max_retries: nil,
|
|
52
|
+
timeout: nil, user_agent: nil, headers: nil, disable_update_notice: false)
|
|
53
|
+
raise ArgumentError, Defaults::MESSAGES[:KEY_TWICE] unless key.nil? || api_key.nil?
|
|
54
|
+
|
|
55
|
+
api_key = key if api_key.nil?
|
|
56
|
+
Credentials.assert_credential(api_key, access_token, required: true)
|
|
57
|
+
|
|
58
|
+
@raw = Transport.new(api_key:, access_token:, base_url:, adapter:, max_retries:, timeout:, user_agent:, headers:,
|
|
59
|
+
disable_update_notice:)
|
|
60
|
+
@mode = Credentials.mode_of(api_key)
|
|
61
|
+
NAMESPACES.each { |name, resource| instance_variable_set(:"@#{name}", resource.new(@raw)) }
|
|
62
|
+
freeze
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def inspect
|
|
66
|
+
"#<#{self.class.name} mode=#{@mode.inspect} base_url=#{@raw.base_url.inspect}>"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|