paubox 1.0.0 → 1.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: da4b3dae43dc155032452be9913d48e4da7ba65878067923af62bb5497783ebc
4
- data.tar.gz: f7e0db657ed86db45207f3c0fcd280febd834262ebcac0313a5c48c0b7e2f186
3
+ metadata.gz: e634770f660fa1456484f19c2ebe520475d5333873f1a1194e05dbe50385c84f
4
+ data.tar.gz: 1552df4218cc138eba73eb402af9ebc55e0a39a65e577a3b95f4e08f56ab274f
5
5
  SHA512:
6
- metadata.gz: b450e2ca12166a1689fc460ec810c11dc6ad53cc2d1e71d29a06f701db91f901d2ead1ca4eb7c61f91ebb444c5caadcbc49c8a5f81157a256514bf90f4b33ac0
7
- data.tar.gz: db478b8679f6acb5a5851b80826f81a1dd0b8360250acd68254812e4cf75c5f4bef83f21c8ec939bd43ec339e0489a554c4bfe271cc246719afcbb93816668c3
6
+ metadata.gz: 7e2b36b9de070e0c35cbf8ccd71c7eda28d6430277eb72ff7ed62fc0f68adc12cd3024f410994342602acde2f780e488ba982c02834887f7d4aa1e9f1d43f81f
7
+ data.tar.gz: bac046b42d9ebb39ce4f9aa692995b27f93a385f47fa1b3d02d1d15dd8cda9e0de0d616c1a86a7245e728a7338758a62a4cb57d31d46117bcfb167d5868cbdbd
@@ -0,0 +1,43 @@
1
+ #!/bin/sh
2
+ # Probes each base URL with a junk token: api.paubox.com answers unrouted paths
3
+ # with its own HTML 404 page, so a wrong base fails here without credentials.
4
+ #
5
+ # Usage: route-check.sh <url> [url ...]
6
+ # <command printing one URL per line> | route-check.sh
7
+ set -eu
8
+
9
+ MARKER='The resource could not be found'
10
+ TOKEN='route-check-not-a-real-key'
11
+
12
+ urls=$(mktemp)
13
+ fails=$(mktemp)
14
+ trap 'rm -f "$urls" "$fails"' EXIT
15
+
16
+ if [ "$#" -gt 0 ]; then
17
+ for u in "$@"; do echo "$u"; done > "$urls"
18
+ else
19
+ cat > "$urls"
20
+ fi
21
+
22
+ sed 's#/*$##' "$urls" | grep '^https://' | sort -u > "$urls.clean" || true
23
+ mv "$urls.clean" "$urls"
24
+
25
+ if [ ! -s "$urls" ]; then
26
+ echo "route-check: no URLs given" >&2
27
+ exit 1
28
+ fi
29
+
30
+ while IFS= read -r url; do
31
+ if curl -sS -m 20 -H "Authorization: Token token=$TOKEN" "$url" \
32
+ | grep -qF "$MARKER"; then
33
+ echo "FAIL $url <- not routed"
34
+ echo "$url" >> "$fails"
35
+ else
36
+ echo "ok $url"
37
+ fi
38
+ done < "$urls"
39
+
40
+ if [ -s "$fails" ]; then
41
+ echo "See https://docs.paubox.com for the documented base URLs." >&2
42
+ exit 1
43
+ fi
@@ -38,3 +38,24 @@ jobs:
38
38
 
39
39
  - name: Assert the suite actually executed
40
40
  run: ruby .github/scripts/assert_specs_ran.rb rspec-results.json
41
+
42
+ route-check:
43
+ name: Base URLs are routed
44
+ runs-on: ubuntu-latest
45
+ steps:
46
+ - uses: actions/checkout@v4
47
+
48
+ - uses: ruby/setup-ruby@v1
49
+ with:
50
+ ruby-version: "3.3"
51
+ bundler-cache: true
52
+
53
+ # Ask the client, so a base URL change cannot pass unprobed.
54
+ - name: Probe the base URLs the clients build
55
+ run: |
56
+ bundle exec ruby -Ilib -rjson -rpaubox -e '
57
+ Paubox.configure { |c| c.api_key = "route-check" }
58
+ puts Paubox::Client.new.send(:api_base_endpoint)
59
+ f = Paubox::FormsClient
60
+ puts "#{f::FORMS_PROTOCOL}#{f::FORMS_HOST}#{f::FORMS_BASE}"
61
+ ' | .github/scripts/route-check.sh
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "1.0.0"
2
+ ".": "1.1.0"
3
3
  }
data/CHANGELOG.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [1.1.0](https://github.com/Paubox/paubox-ruby/compare/v1.0.0...v1.1.0) (2026-09-09)
6
+
7
+
8
+ ### Features
9
+
10
+ * add scheduled send support ([#26](https://github.com/Paubox/paubox-ruby/issues/26)) ([9ddb07a](https://github.com/Paubox/paubox-ruby/commit/9ddb07a20f41874a10be6e0479cb943e833b336d))
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * target the documented /v1/email and /v1/forms base URLs ([#24](https://github.com/Paubox/paubox-ruby/issues/24)) ([3a32459](https://github.com/Paubox/paubox-ruby/commit/3a324596ef8e9237d5da15246b36a21baf3df688))
16
+
5
17
  ## [1.0.0](https://github.com/Paubox/paubox-ruby/compare/v0.3.2...v1.0.0) (2026-08-21)
6
18
 
7
19
  First stable release. RubyGems had been on `0.3.2` since October 2022.
data/CLAUDE.md CHANGED
@@ -15,7 +15,7 @@ lib/
15
15
  paubox/
16
16
  version.rb # Gem version constant
17
17
  client.rb # Email API client (authenticated, api.paubox.com)
18
- forms_client.rb # Forms API client (api.paubox.com/forms; Bearer auth on management endpoints)
18
+ forms_client.rb # Forms API client (api.paubox.com/v1/forms; Bearer auth on management endpoints)
19
19
  message.rb # Builds send-message API payload from a hash
20
20
  templated_message.rb # Extends Message for template-based sends
21
21
  mail_to_message.rb # Adapts Ruby Mail::Message to API payload
@@ -38,8 +38,8 @@ spec/
38
38
 
39
39
  | Class | Responsibility |
40
40
  |---|---|
41
- | `Paubox::Client` | Authenticated HTTP client for the Email API. Token auth via `Authorization: Token token=<key>`. Base URL: `https://api.paubox.com/v1`. |
42
- | `Paubox::FormsClient` | HTTP client for the Forms API. Base URL: `https://api.paubox.com/forms`. Public endpoints (`get_form`, `submit_form`) send no auth headers; management endpoints (list/create/find/update/archive/copy forms, stats, submissions, CSV/PDF export) require a "forms"-scoped API key sent as `Authorization: Bearer <api_key>`. |
41
+ | `Paubox::Client` | Authenticated HTTP client for the Email API. Token auth via `Authorization: Token token=<key>`. Base URL: `https://api.paubox.com/v1/email`. |
42
+ | `Paubox::FormsClient` | HTTP client for the Forms API. Base URL: `https://api.paubox.com/v1/forms`. Public endpoints (`get_form`, `submit_form`) send no auth headers; management endpoints (list/create/find/update/archive/copy forms, stats, submissions, CSV/PDF export) require a "forms"-scoped API key sent as `Authorization: Bearer <api_key>`. |
43
43
  | `Paubox::Message` | Builds the JSON payload for `/messages`. Accepts `from`, `to`, `cc`, `bcc`, `subject`, `text_content`, `html_content`, `attachments`. |
44
44
  | `Paubox::TemplatedMessage` | Extends `Message`; overrides `send_message_payload` to include `template_name` / `template_values`. |
45
45
  | `Paubox::MailToMessage` | Converts a `Mail::Message` object into a Paubox API payload. |
data/api.md CHANGED
@@ -28,7 +28,7 @@ Authorization: Token token=<api_key>
28
28
  ### Base URL
29
29
 
30
30
  ```
31
- https://api.paubox.com/v1
31
+ https://api.paubox.com/v1/email
32
32
  ```
33
33
 
34
34
  All Email API paths below are relative to this base.
@@ -178,7 +178,7 @@ Returns service health. No authentication required in practice.
178
178
  ### Base URL
179
179
 
180
180
  ```
181
- https://api.paubox.com/forms
181
+ https://api.paubox.com/v1/forms
182
182
  ```
183
183
 
184
184
  ---
data/lib/paubox/client.rb CHANGED
@@ -54,6 +54,43 @@ module Paubox
54
54
  end
55
55
  alias message_receipt email_disposition
56
56
 
57
+ def schedule_mail(mail, scheduled_at)
58
+ case mail
59
+ when Mail::Message
60
+ allow_non_tls = mail.allow_non_tls.nil? ? false : mail.allow_non_tls
61
+ msg_payload = MailToMessage.new(mail, allow_non_tls: allow_non_tls).send_message_payload
62
+ msg_data = JSON.parse(msg_payload)['data']['message']
63
+ when Hash
64
+ msg_data = Message.new(mail).send_message_payload
65
+ msg_data = JSON.parse(msg_data)['data']['message']
66
+ when Paubox::Message
67
+ msg_data = JSON.parse(mail.send_message_payload)['data']['message']
68
+ end
69
+ payload = { data: { message: msg_data, scheduled_at: scheduled_at } }.to_json
70
+ url = request_endpoint('schedule')
71
+ response = RestClient.post(url, payload, auth_header)
72
+ JSON.parse(response.body)
73
+ end
74
+
75
+ def get_scheduled(source_tracking_id)
76
+ url = request_endpoint("schedule/#{source_tracking_id}")
77
+ response = RestClient.get(url, auth_header)
78
+ JSON.parse(response.body)
79
+ end
80
+
81
+ def reschedule(source_tracking_id, scheduled_at)
82
+ url = request_endpoint("schedule/#{source_tracking_id}")
83
+ payload = { scheduled_at: scheduled_at }.to_json
84
+ response = RestClient.patch(url, payload, auth_header)
85
+ JSON.parse(response.body)
86
+ end
87
+
88
+ def cancel_scheduled(source_tracking_id)
89
+ url = request_endpoint("schedule/#{source_tracking_id}/cancel")
90
+ response = RestClient.post(url, nil, auth_header)
91
+ JSON.parse(response.body)
92
+ end
93
+
57
94
  def send_request(method: :get, payload: {}, path: '')
58
95
  url = request_endpoint(path)
59
96
 
@@ -69,7 +106,7 @@ module Paubox
69
106
  end
70
107
 
71
108
  def api_base_endpoint
72
- "#{api_protocol}#{api_host}/#{api_version}"
109
+ "#{api_protocol}#{api_host}/#{api_version}/email"
73
110
  end
74
111
 
75
112
  def request_endpoint(endpoint)
@@ -7,7 +7,7 @@ module Paubox
7
7
  class FormsClient
8
8
  FORMS_HOST = 'api.paubox.com'
9
9
  FORMS_PROTOCOL = 'https://'
10
- FORMS_BASE = '/forms'
10
+ FORMS_BASE = '/v1/forms'
11
11
 
12
12
  TIMEOUT_SECONDS = 30
13
13
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Paubox
4
- VERSION = '1.0.0'
4
+ VERSION = '1.1.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paubox
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paubox
@@ -149,6 +149,7 @@ extensions: []
149
149
  extra_rdoc_files: []
150
150
  files:
151
151
  - ".github/scripts/assert_specs_ran.rb"
152
+ - ".github/scripts/route-check.sh"
152
153
  - ".github/workflows/ci.yml"
153
154
  - ".github/workflows/pr-title.yml"
154
155
  - ".github/workflows/release-please.yml"