unisender-ruby 0.1.1 → 0.2.0
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 +4 -4
- data/CHANGELOG.md +89 -0
- data/CONTRIBUTING.md +10 -1
- data/README.md +55 -112
- data/docs/api.md +395 -210
- data/docs/execution.md +89 -0
- data/docs/import-recovery.md +41 -0
- data/docs/live-contracts.md +34 -0
- data/docs/migration-0.2.md +129 -0
- data/docs/rails.md +248 -0
- data/docs/releases.md +4 -4
- data/docs/testing.md +83 -0
- data/docs/usage.md +144 -0
- data/docs/webhooks.md +41 -0
- data/examples/campaign.rb +5 -6
- data/examples/campaign_lifecycle.rb +28 -0
- data/examples/check_connection.rb +1 -1
- data/examples/events.rb +1 -1
- data/examples/export.rb +20 -6
- data/examples/import.rb +3 -2
- data/examples/import_recovery.rb +70 -0
- data/examples/quickstart.rb +1 -1
- data/examples/subscribe.rb +2 -2
- data/lib/unisender/acceptance.rb +104 -0
- data/lib/unisender/attachment.rb +47 -0
- data/lib/unisender/batch_report.rb +115 -0
- data/lib/unisender/batch_summary.rb +87 -0
- data/lib/unisender/batches.rb +41 -12
- data/lib/unisender/campaign_workflow.rb +72 -0
- data/lib/unisender/client.rb +65 -33
- data/lib/unisender/client_configuration.rb +50 -0
- data/lib/unisender/client_execution.rb +43 -0
- data/lib/unisender/client_state.rb +31 -0
- data/lib/unisender/client_validation.rb +97 -0
- data/lib/unisender/configuration.rb +151 -0
- data/lib/unisender/contact_records.rb +251 -0
- data/lib/unisender/diagnostic_urls.rb +68 -0
- data/lib/unisender/diagnostics.rb +83 -0
- data/lib/unisender/download_target.rb +61 -0
- data/lib/unisender/download_transfer.rb +43 -0
- data/lib/unisender/downloader.rb +99 -0
- data/lib/unisender/error_diagnostics.rb +83 -0
- data/lib/unisender/errors.rb +125 -8
- data/lib/unisender/event_batches.rb +40 -0
- data/lib/unisender/event_payload.rb +50 -22
- data/lib/unisender/events.rb +21 -5
- data/lib/unisender/execution_context.rb +114 -0
- data/lib/unisender/form.rb +20 -12
- data/lib/unisender/helpers.rb +70 -10
- data/lib/unisender/hooks.rb +79 -0
- data/lib/unisender/import_cells.rb +62 -0
- data/lib/unisender/input_types.rb +30 -0
- data/lib/unisender/inputs.rb +262 -0
- data/lib/unisender/iteration.rb +15 -0
- data/lib/unisender/iterators.rb +60 -0
- data/lib/unisender/mail_inputs.rb +37 -0
- data/lib/unisender/named_inputs.rb +52 -0
- data/lib/unisender/observation.rb +30 -0
- data/lib/unisender/operation_contracts.rb +106 -0
- data/lib/unisender/operations/contacts_1.rb +4 -3
- data/lib/unisender/operations/contacts_2.rb +23 -4
- data/lib/unisender/operations/messages_1.rb +7 -4
- data/lib/unisender/operations/messages_2.rb +8 -3
- data/lib/unisender/operations/messages_3.rb +1 -1
- data/lib/unisender/operations/notes_1.rb +1 -1
- data/lib/unisender/operations/statistics_1.rb +3 -3
- data/lib/unisender/operations/templates_1.rb +2 -2
- data/lib/unisender/outcomes.rb +320 -0
- data/lib/unisender/page_response.rb +48 -0
- data/lib/unisender/paginated_operations.rb +43 -2
- data/lib/unisender/pagination.rb +53 -20
- data/lib/unisender/persistent_transport.rb +104 -0
- data/lib/unisender/rate_limiter.rb +72 -0
- data/lib/unisender/record.rb +210 -0
- data/lib/unisender/record_rows.rb +69 -0
- data/lib/unisender/records.rb +614 -0
- data/lib/unisender/request_execution.rb +108 -0
- data/lib/unisender/response.rb +13 -10
- data/lib/unisender/result_registry.rb +72 -0
- data/lib/unisender/results.rb +105 -0
- data/lib/unisender/retry_policy.rb +10 -16
- data/lib/unisender/serialization.rb +54 -0
- data/lib/unisender/statistic_records.rb +129 -0
- data/lib/unisender/task_response.rb +85 -0
- data/lib/unisender/task_waiter.rb +25 -11
- data/lib/unisender/testing/assertions.rb +48 -0
- data/lib/unisender/testing/fixtures.rb +24 -0
- data/lib/unisender/testing.rb +91 -0
- data/lib/unisender/transport.rb +17 -9
- data/lib/unisender/validation.rb +11 -9
- data/lib/unisender/version.rb +1 -1
- data/lib/unisender/webhooks/tokens.rb +38 -0
- data/lib/unisender/webhooks.rb +230 -0
- data/lib/unisender.rb +42 -0
- data/sig/acceptance.rbs +30 -0
- data/sig/attachment.rbs +15 -0
- data/sig/batch_summary.rbs +38 -0
- data/sig/campaign_workflow.rbs +20 -0
- data/sig/configuration.rbs +62 -0
- data/sig/connection_controls.rbs +55 -0
- data/sig/diagnostics.rbs +37 -0
- data/sig/domain_records.rbs +96 -0
- data/sig/downloads.rbs +53 -0
- data/sig/execution.rbs +52 -0
- data/sig/execution_context.rbs +46 -0
- data/sig/hooks.rbs +18 -0
- data/sig/inputs.rbs +84 -0
- data/sig/iterators.rbs +11 -0
- data/sig/mail_inputs.rbs +8 -0
- data/sig/manifest.yaml +11 -0
- data/sig/operation_contracts.rbs +28 -0
- data/sig/operations.rbs +73 -69
- data/sig/outcomes.rbs +90 -0
- data/sig/record.rbs +77 -0
- data/sig/records.rbs +182 -0
- data/sig/serialization.rbs +13 -0
- data/sig/tasks.rbs +26 -0
- data/sig/testing.rbs +54 -0
- data/sig/unisender.rbs +128 -39
- data/sig/webhooks.rbs +55 -0
- metadata +84 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f3678167b25f05feee7a6cbb24ead0d09fea765de2cbd815f092644c1ee62598
|
|
4
|
+
data.tar.gz: c0d66eec6a7c5ea4b93e162a7c4ebc62c9548585c6e4cf3cc5f49a50d345f0b5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8c15b5e69db9bb9584e75c52a1666ed99cf5cae211be9acf9b154943068e1f168803d332b2e907ec8ab4dccbec1ad7faceb3685a7006eaad4e97bb70b3ca5c8e
|
|
7
|
+
data.tar.gz: a634d99895b18c0df41f1e5b01f1943ca15f56e9921624be600c0be5b0eaf9b6e5e8745b7cb2d5e20c521127b679f8e0190a1fcf56dee239a788d96157e06a49
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,95 @@ Unreleased collects changes for the next version. Dated sections list user-visib
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.2.0 - 2026-10-26
|
|
8
|
+
|
|
9
|
+
- Parse diagnostic bracket fields without regex substitution while preserving index paths and redaction.
|
|
10
|
+
|
|
11
|
+
- Add campaign lifecycle and durable import examples, a complete Rails integration, verified Cursor setup, and shorter task-oriented documentation.
|
|
12
|
+
|
|
13
|
+
- Keep offline pagination validation aligned with execution and report indexed event and response-shape errors.
|
|
14
|
+
- Mark acceptance as uncertain when responses omit inputs or return inconsistent counts; enforce false JSON expectations.
|
|
15
|
+
|
|
16
|
+
- Add optional fixture builders and redacted subset assertions for queued form and JSON requests.
|
|
17
|
+
|
|
18
|
+
- Add optional acceptance instrumentation with separate accepted, rejected, and unknown counts for sends, imports, and events.
|
|
19
|
+
|
|
20
|
+
- Identify API requests with the gem and Ruby versions and document client ownership across variants, threads, and forks.
|
|
21
|
+
|
|
22
|
+
- Add redacted error diagnostics, structural field paths, expected and actual types, and request context on malformed responses.
|
|
23
|
+
|
|
24
|
+
- Add an independent optional Event Tracking rate limiter and validate message-default containers locally.
|
|
25
|
+
|
|
26
|
+
- Add named mail headers, image-mode symbols, and explicit accepted, rejected, and unknown recipient views.
|
|
27
|
+
|
|
28
|
+
- Accept SMS phone arrays and always return a typed receipt collection.
|
|
29
|
+
|
|
30
|
+
- Give records class-sensitive value equality, forward object lookup, and avoid polling failed task handles.
|
|
31
|
+
|
|
32
|
+
- Honor top-level `only` and `except` JSON filters and reject unsupported serialization options.
|
|
33
|
+
|
|
34
|
+
- Validate named argument types locally and expose offline `Client#validate!` with shared normalization and encoding.
|
|
35
|
+
|
|
36
|
+
- Bound direct imports to 501 inspected records and add optional byte limits to attachment reads.
|
|
37
|
+
|
|
38
|
+
- Schedule Time inputs in explicit UTC with minute precision; reject conflicting timezones.
|
|
39
|
+
|
|
40
|
+
- Document the accepted MD5 exception required by UniSender's webhook protocol.
|
|
41
|
+
|
|
42
|
+
- Scan webhook JSON tokens without regular-expression backtracking and reject unterminated strings.
|
|
43
|
+
- Escape backslashes as well as table separators in generated API type descriptions.
|
|
44
|
+
|
|
45
|
+
- Preserve existing injected retry policies, rate limiters, and downloaders when execution scopes are enabled.
|
|
46
|
+
- Add cooperative execution scopes and cancellation across retries, pacing, polling, and batch boundaries, with separate execution timing events and request IDs on request events.
|
|
47
|
+
- Add opt-in summary retention and progress checkpoints for import and Event Tracking batches, preserving known source offsets for row diagnostics.
|
|
48
|
+
- Add hook management and bounded JSON/gzip webhook authentication with typed notification readers.
|
|
49
|
+
- Add fake-transport queue verification and JSON request access, durable export recovery examples, and opt-in staging contract probes.
|
|
50
|
+
|
|
51
|
+
- Validate malformed contact fields and count filters locally, and preserve operation names and import column paths in validation errors.
|
|
52
|
+
- Correct reference descriptions of legacy empty-result normalization.
|
|
53
|
+
|
|
54
|
+
- Standardize input diagnostics, validate named flags and choices, and preserve wrapper failure context.
|
|
55
|
+
- Normalize structured import cells and expose typed row warnings with known global indices.
|
|
56
|
+
- Add scoped email/phone removal inputs and explicit contact-count filters.
|
|
57
|
+
- Request detailed send acceptance by default; retain explicit legacy and omission options.
|
|
58
|
+
|
|
59
|
+
- Accept blocks on page iterators and expose page checkpoint offsets.
|
|
60
|
+
- Add Array-style collection access, Hash-style record lookup, and payload JSON serialization.
|
|
61
|
+
- Add stable contact address readers, optional contact details, note metadata, and mutation result readers.
|
|
62
|
+
- Return completed task handles without polling; expose task predicates and block-scoped client lifetime.
|
|
63
|
+
|
|
64
|
+
- Separate development installation from published usage and link gem documentation to its version tag.
|
|
65
|
+
- Generate API argument and result tables from RBS, with agreement checks for the Ruby interface.
|
|
66
|
+
|
|
67
|
+
- Expose all documented import counters directly and normalize string-keyed default overrides.
|
|
68
|
+
- Validate campaign encoding before creating a message.
|
|
69
|
+
|
|
70
|
+
- Preserve accepted batches on source exceptions and task context on polling request failures.
|
|
71
|
+
- Validate direct pagination controls and include named-result failures in instrumentation.
|
|
72
|
+
- Reject special-use download addresses and complete Time signatures for iterators.
|
|
73
|
+
|
|
74
|
+
- Add opt-in persistent HTTPS connections, lifecycle controls, and shared process-local request pacing.
|
|
75
|
+
- Add binary attachment snapshots and a preflighted create-message/send-campaign workflow.
|
|
76
|
+
- Add explicit, bounded export downloads without forwarding API credentials.
|
|
77
|
+
|
|
78
|
+
- Add direct timeout and retry options, environment construction, immutable variants, and message defaults.
|
|
79
|
+
- Add safe request instrumentation, structured error categories, recovery hints, and retry-safety checks.
|
|
80
|
+
- Ship optional test transport support and application integration guides.
|
|
81
|
+
- Expand typed contact, sender-domain, SMS, and campaign-statistics results.
|
|
82
|
+
|
|
83
|
+
- Expose typed acceptance reports and global batch failure indices without replaying requests.
|
|
84
|
+
- Split event batches by encoded bytes and count; preserve completed work when input enumeration fails.
|
|
85
|
+
|
|
86
|
+
- Accept contact records, named subscription modes, and Ruby time inputs.
|
|
87
|
+
- Add task handles with explicit polling, progress callbacks, and contextual timeout errors.
|
|
88
|
+
|
|
89
|
+
- Execute batch commands immediately; provide explicit lazy batch and typed item iterators.
|
|
90
|
+
- Add page navigation with resume offsets and immediate argument validation.
|
|
91
|
+
|
|
92
|
+
- Return typed immutable records and enumerable collections from named operations.
|
|
93
|
+
- Add direct field access, a boolean membership predicate, and singular message results.
|
|
94
|
+
- Rename response HTTP metadata to `http_status`; preserve upstream JSON through `data`.
|
|
95
|
+
|
|
7
96
|
## 0.1.1 - 2026-10-25
|
|
8
97
|
|
|
9
98
|
- Clarify installation, example destinations, contribution guidance, and maintainer policies.
|
data/CONTRIBUTING.md
CHANGED
|
@@ -39,9 +39,18 @@ Pre-commit hooks scan staged changes for secrets, apply and stage safe Ruby form
|
|
|
39
39
|
|
|
40
40
|
## Build and test the package
|
|
41
41
|
|
|
42
|
+
API reference tables come from shipped RBS signatures and `docs/api_annotations.yml`.
|
|
43
|
+
After changing either, regenerate the tables:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
bundle exec ruby -r ./scripts/api_reference -e 'File.write("docs/api.md", APIReference.new(Dir.pwd).render)'
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The regular test suite checks that generated tables match the public Ruby keywords.
|
|
50
|
+
|
|
42
51
|
```sh
|
|
43
52
|
bundle exec rake build
|
|
44
|
-
gem install --local
|
|
53
|
+
ruby -e 'spec = Gem::Specification.load("unisender.gemspec"); system("gem", "install", "--local", "pkg/#{spec.file_name}") || abort("Install failed")'
|
|
45
54
|
```
|
|
46
55
|
|
|
47
56
|
From outside the checkout, run `ruby -runisender -e 'puts Unisender::VERSION'`. For an isolated check, use a temporary `GEM_HOME` and `GEM_PATH`, and run the examples with a fake transport. The gem includes examples and RBS signatures; development dependencies are not runtime dependencies.
|
data/README.md
CHANGED
|
@@ -2,71 +2,50 @@
|
|
|
2
2
|
|
|
3
3
|
A Ruby client for applications using the [UniSender marketing API](https://www.unisender.com/ru/support/category/api/).
|
|
4
4
|
|
|
5
|
-
Ruby 3.3 or newer, no runtime gem dependencies.
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
- Ruby 3.3 or newer, with no runtime gem dependencies.
|
|
6
|
+
- Contacts, lists, messages, campaigns, statistics, templates, fields, notes, and Event Tracking.
|
|
7
|
+
- Typed immutable results, offline validation, and explicit pagination and batch recovery.
|
|
8
|
+
- Targets `api.unisender.com` and Event Tracking, not UniSender Go.
|
|
8
9
|
|
|
9
10
|
## Install
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
```sh
|
|
14
|
-
gem install unisender-ruby
|
|
15
|
-
```
|
|
12
|
+
This guide covers version 0.2. See the [migration guide](docs/migration-0.2.md) when upgrading from 0.1.
|
|
16
13
|
|
|
17
|
-
|
|
14
|
+
Add the gem to your application's `Gemfile`:
|
|
18
15
|
|
|
19
|
-
<!-- example: examples/quickstart.rb -->
|
|
20
16
|
```ruby
|
|
21
|
-
require "unisender"
|
|
22
|
-
|
|
23
|
-
client = Unisender::Client.new(api_key: ENV.fetch("UNISENDER_API_KEY"))
|
|
24
|
-
client.get_lists.result.each { |list| puts list.fetch("title") }
|
|
25
|
-
# Example output for a list named News: News
|
|
17
|
+
gem "unisender-ruby", "~> 0.2.0", require: "unisender"
|
|
26
18
|
```
|
|
27
19
|
|
|
28
|
-
Run `
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
```ruby
|
|
33
|
-
gem "unisender-ruby", "~> 0.1.1", require: "unisender"
|
|
34
|
-
```
|
|
20
|
+
Run `bundle install`.
|
|
21
|
+
To build from a checkout, follow [build and installation](CONTRIBUTING.md#build-and-test-the-package).
|
|
22
|
+
The package name is `unisender-ruby`; the Ruby load path is `unisender`.
|
|
35
23
|
|
|
36
|
-
|
|
24
|
+
## Read your lists
|
|
37
25
|
|
|
38
|
-
|
|
26
|
+
Get your key from [UniSender's API settings](https://www.unisender.com/ru/support/api/common/api-key/).
|
|
27
|
+
Set `UNISENDER_API_KEY` through your shell or application's secret store.
|
|
28
|
+
The library does not load `.env` files. Keep credentials out of source and logs.
|
|
39
29
|
|
|
40
|
-
|
|
30
|
+
Save this as `quickstart.rb`:
|
|
41
31
|
|
|
32
|
+
<!-- example: examples/quickstart.rb -->
|
|
42
33
|
```ruby
|
|
43
|
-
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Adjust the path, then run `bundle install`. Alternatively, build and install the local package as described in [CONTRIBUTING.md](CONTRIBUTING.md#build-and-test-the-package).
|
|
47
|
-
|
|
48
|
-
## Make your first request
|
|
49
|
-
|
|
50
|
-
Get your key from [UniSender's API settings](https://www.unisender.com/ru/support/api/common/api-key/) and put it in the `UNISENDER_API_KEY` environment variable through your shell or application's secret store. Keep it out of source control and logs.
|
|
51
|
-
|
|
52
|
-
For a local checkout, you can store `UNISENDER_API_KEY=your-key` in `.env`, which Git ignores. Ruby does not load this file automatically. Load your own `.env` into the current shell, then run the read-only connection check:
|
|
34
|
+
require "unisender"
|
|
53
35
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
set +a
|
|
58
|
-
bundle exec ruby examples/check_connection.rb
|
|
36
|
+
client = Unisender::Client.new(api_key: ENV.fetch("UNISENDER_API_KEY"))
|
|
37
|
+
client.get_lists.each { |list| puts list.title }
|
|
38
|
+
# Example output for a list named News: News
|
|
59
39
|
```
|
|
60
40
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
The `quickstart.rb` example above only reads lists. It does not create contacts or send messages. In a Bundler project, run it with `bundle exec ruby quickstart.rb`. A missing environment variable raises `KeyError` before any request. To try the client without an account or network access, run `bundle exec ruby examples/offline.rb` from this checkout.
|
|
41
|
+
Run `bundle exec ruby quickstart.rb`. An empty account prints nothing.
|
|
42
|
+
To try the client without credentials, run `bundle exec ruby examples/offline.rb` from the checkout.
|
|
64
43
|
|
|
65
44
|
## Subscribe a contact
|
|
66
45
|
|
|
67
|
-
This
|
|
68
|
-
|
|
69
|
-
Save
|
|
46
|
+
This changes your account and normally **sends a confirmation email**.
|
|
47
|
+
Set `UNISENDER_LIST_ID` to an existing list and `UNISENDER_CONTACT_EMAIL` to an address you control.
|
|
48
|
+
Save this as `subscribe.rb`:
|
|
70
49
|
|
|
71
50
|
<!-- example: examples/subscribe.rb -->
|
|
72
51
|
```ruby
|
|
@@ -75,86 +54,50 @@ require "unisender"
|
|
|
75
54
|
client = Unisender::Client.new(api_key: ENV.fetch("UNISENDER_API_KEY"))
|
|
76
55
|
response = client.subscribe(
|
|
77
56
|
list_ids: [ENV.fetch("UNISENDER_LIST_ID")],
|
|
78
|
-
|
|
57
|
+
email: ENV.fetch("UNISENDER_CONTACT_EMAIL")
|
|
79
58
|
)
|
|
80
|
-
puts response.
|
|
59
|
+
puts response.person_id
|
|
81
60
|
```
|
|
82
61
|
|
|
83
|
-
The contact must confirm before receiving campaigns.
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
Each example is a standalone Ruby file. Its header lists required environment variables and account effects.
|
|
62
|
+
Run `bundle exec ruby subscribe.rb`. The contact must confirm before receiving campaigns.
|
|
63
|
+
Use `double_optin: :already_confirmed` only with consent already established.
|
|
64
|
+
To check inputs without networking, call `client.validate!(:subscribe, list_ids: [123], email: "person@example.test")`.
|
|
88
65
|
|
|
89
|
-
|
|
90
|
-
| --- | --- | --- |
|
|
91
|
-
| Read lists | [quickstart.rb](examples/quickstart.rb) | Read only |
|
|
92
|
-
| Check credentials without printing account data | [check_connection.rb](examples/check_connection.rb) | Read only |
|
|
93
|
-
| Test without credentials | [offline.rb](examples/offline.rb) | No network |
|
|
94
|
-
| Subscribe a contact | [subscribe.rb](examples/subscribe.rb) | Changes contacts; sends confirmation |
|
|
95
|
-
| Create and send a campaign | [campaign.rb](examples/campaign.rb) | Sends to the selected list |
|
|
96
|
-
| Export contacts | [export.rb](examples/export.rb) | Starts and polls an export job |
|
|
97
|
-
| Import batches with partial-failure handling | [import.rb](examples/import.rb) | Changes contacts |
|
|
98
|
-
| Track events with partial-failure handling | [events.rb](examples/events.rb) | Records events; can trigger automation |
|
|
66
|
+
## Handle a failure
|
|
99
67
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
Every operation returns `Unisender::Response`: `result`, `warnings`, `data` (the full JSON object), `status`, and `headers`. Values are deeply immutable. JSON keys are strings; numbers are not coerced. Read or copy the data explicitly when your application needs to change it.
|
|
103
|
-
|
|
104
|
-
Named methods use snake_case and reject unknown keywords. Optional `nil` values are omitted, preserving server defaults. API messages default to English; use `Client.new(api_key: ..., language: :ru)` for Russian. Message-level `lang:` is a separate setting.
|
|
105
|
-
|
|
106
|
-
Use this error handler in your application's `request.rb`:
|
|
68
|
+
Put error handling around calls in your application:
|
|
107
69
|
|
|
108
70
|
```ruby
|
|
109
71
|
begin
|
|
110
72
|
client.get_lists
|
|
111
|
-
rescue Unisender::
|
|
112
|
-
warn error.
|
|
113
|
-
# Fix credentials, permissions, or parameters using error.code.
|
|
114
|
-
rescue Unisender::HTTPError => error
|
|
115
|
-
warn error.message
|
|
116
|
-
# Check error.response.status and error.response.headers.
|
|
117
|
-
rescue Unisender::TransportError, Unisender::InvalidResponseError => error
|
|
118
|
-
warn error.message
|
|
119
|
-
# Check service availability before deciding whether to repeat the operation.
|
|
73
|
+
rescue Unisender::Error => error
|
|
74
|
+
warn error.diagnostics.inspect
|
|
120
75
|
end
|
|
121
76
|
```
|
|
122
77
|
|
|
123
|
-
`
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
A successful envelope does not mean every recipient succeeded. Inspect `send_email(error_checking: 1, ...)` recipient errors and import counters. A `BatchError` provides `completed_responses`, the zero-based, end-exclusive `failed_range`, and the original `error`. Accepted changes remain applied; do not repeat the whole input automatically. The [batch example](examples/import.rb) shows how to inspect partial results.
|
|
128
|
-
|
|
129
|
-
## Timeouts, retries, and pagination
|
|
130
|
-
|
|
131
|
-
In `quickstart.rb`, replace the client construction with:
|
|
132
|
-
|
|
133
|
-
```ruby
|
|
134
|
-
client = Unisender::Client.new(
|
|
135
|
-
api_key: ENV.fetch("UNISENDER_API_KEY"),
|
|
136
|
-
transport: Unisender::Transport.new(open_timeout: 5, read_timeout: 60, write_timeout: 30),
|
|
137
|
-
retry_policy: Unisender::RetryPolicy.new(max_retries: 2, max_elapsed: 60)
|
|
138
|
-
)
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
Those are the default transport timeouts in seconds. TLS certificates are verified, redirects are rejected, and calls do not share connections. **Retries default to zero.** The opt-in policy retries only explicitly identified read-only operations, at most twice, with backoff, jitter, and `Retry-After`. Sends, mutations, imports, exports, events, and unknown methods are never retried automatically. The elapsed retry budget is not a hard request deadline; in-flight requests use transport timeouts.
|
|
142
|
-
|
|
143
|
-
`each_page` and batch helpers return lazy Enumerators: **consume them to make requests**. Stopping enumeration prevents subsequent requests. `each_page` yields responses, accepts a supported Ruby method name, and raises `PaginationError` at `max_pages`. `wait_for_task` polls an existing job; its deadline is checked between requests. See [helper limits and recovery behavior](docs/api.md#convenience-operations) and [upstream rate limits](https://www.unisender.com/ru/support/api/common/api-limits/).
|
|
144
|
-
|
|
145
|
-
## Low-level access and types
|
|
146
|
-
|
|
147
|
-
`client.request("getLists", params: {})` accepts exact upstream names. It handles authentication, encoding, and failures, but does not perform operation-specific conversions. Comma-separated fields must already be strings; nested arrays and hashes become bracketed form fields. Credentials and JSON format cannot be overridden.
|
|
78
|
+
`diagnostics` omits credentials and payloads. Local input errors raise `Unisender::ValidationError`, an `ArgumentError` subclass.
|
|
79
|
+
A successful request can still reject recipients. Inspect `complete?`, `partial?`, and `uncertain?` on acceptance reports.
|
|
80
|
+
Retries default to zero. Sends and mutations are never automatically retried.
|
|
148
81
|
|
|
149
|
-
|
|
82
|
+
## Find your task
|
|
150
83
|
|
|
151
|
-
|
|
84
|
+
| Task | Guide or example |
|
|
85
|
+
| --- | --- |
|
|
86
|
+
| Choose an operation or find a keyword | [API reference](docs/api.md) |
|
|
87
|
+
| Read results, configure clients, handle errors | [Usage guide](docs/usage.md) |
|
|
88
|
+
| Create, inspect, test, and schedule a campaign | [Campaign lifecycle](examples/campaign_lifecycle.rb) |
|
|
89
|
+
| Recover an import from durable checkpoints | [Import recovery](docs/import-recovery.md) |
|
|
90
|
+
| Export and download contacts | [Export example](examples/export.rb) |
|
|
91
|
+
| Record events | [Event example](examples/events.rb) |
|
|
92
|
+
| Test an application or configure Cursor | [Testing and editor setup](docs/testing.md) |
|
|
93
|
+
| Integrate Rails jobs and delivery webhooks | [Rails guide](docs/rails.md) |
|
|
94
|
+
| Control pacing, cancellation, and resource ownership | [Execution guide](docs/execution.md) |
|
|
95
|
+
| Upgrade from 0.1 | [Migration guide](docs/migration-0.2.md) |
|
|
152
96
|
|
|
153
|
-
|
|
154
|
-
- [Changes and compatibility policy](CHANGELOG.md)
|
|
155
|
-
- [Release verification](docs/releases.md)
|
|
156
|
-
- [Source repository](https://github.com/svyatov/unisender-ruby) and [issue reports](https://github.com/svyatov/unisender-ruby/issues)
|
|
97
|
+
## Help and project status
|
|
157
98
|
|
|
158
|
-
|
|
99
|
+
Leonid Svyatov maintains this project. Use the public [issue tracker](https://github.com/svyatov/unisender-ruby/issues) for questions and defects.
|
|
100
|
+
Report vulnerabilities privately through [SECURITY.md](SECURITY.md).
|
|
159
101
|
|
|
160
|
-
|
|
102
|
+
See [contributing](CONTRIBUTING.md), [changes](CHANGELOG.md), [release verification](docs/releases.md), and the [MIT license](LICENSE.txt).
|
|
103
|
+
Tests use fake credentials and deterministic responses. Live account compatibility requires separate [staging checks](docs/live-contracts.md).
|