sf-queue-sdk 0.2.0b24__tar.gz → 0.2.0b25__tar.gz

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.
Files changed (24) hide show
  1. sf_queue_sdk-0.2.0b24/README.md → sf_queue_sdk-0.2.0b25/PKG-INFO +35 -0
  2. sf_queue_sdk-0.2.0b24/PKG-INFO → sf_queue_sdk-0.2.0b25/README.md +27 -8
  3. {sf_queue_sdk-0.2.0b24 → sf_queue_sdk-0.2.0b25}/pyproject.toml +1 -1
  4. {sf_queue_sdk-0.2.0b24 → sf_queue_sdk-0.2.0b25}/queue_sdk/__init__.py +1 -1
  5. {sf_queue_sdk-0.2.0b24 → sf_queue_sdk-0.2.0b25}/queue_sdk/generated/queue/email/v1/email_pb2.py +10 -10
  6. {sf_queue_sdk-0.2.0b24 → sf_queue_sdk-0.2.0b25}/queue_sdk/generated/queue/email/v1/email_pb2.pyi +12 -4
  7. {sf_queue_sdk-0.2.0b24 → sf_queue_sdk-0.2.0b25}/queue_sdk/generated/queue/tool_assignment/v1/tool_assignment_pb2.py +4 -4
  8. {sf_queue_sdk-0.2.0b24 → sf_queue_sdk-0.2.0b25}/queue_sdk/generated/queue/topic_assignment/v1/topic_assignment_pb2.py +4 -4
  9. {sf_queue_sdk-0.2.0b24 → sf_queue_sdk-0.2.0b25}/queue_sdk/queues/email_queue.py +33 -5
  10. {sf_queue_sdk-0.2.0b24 → sf_queue_sdk-0.2.0b25}/queue_sdk/types.py +4 -0
  11. {sf_queue_sdk-0.2.0b24 → sf_queue_sdk-0.2.0b25}/.gitignore +0 -0
  12. {sf_queue_sdk-0.2.0b24 → sf_queue_sdk-0.2.0b25}/queue_sdk/client.py +0 -0
  13. {sf_queue_sdk-0.2.0b24 → sf_queue_sdk-0.2.0b25}/queue_sdk/generated/__init__.py +0 -0
  14. {sf_queue_sdk-0.2.0b24 → sf_queue_sdk-0.2.0b25}/queue_sdk/generated/queue/tool_assignment/v1/tool_assignment_pb2.pyi +0 -0
  15. {sf_queue_sdk-0.2.0b24 → sf_queue_sdk-0.2.0b25}/queue_sdk/generated/queue/topic_assignment/v1/topic_assignment_pb2.pyi +0 -0
  16. {sf_queue_sdk-0.2.0b24 → sf_queue_sdk-0.2.0b25}/queue_sdk/query.py +0 -0
  17. {sf_queue_sdk-0.2.0b24 → sf_queue_sdk-0.2.0b25}/queue_sdk/queues/__init__.py +0 -0
  18. {sf_queue_sdk-0.2.0b24 → sf_queue_sdk-0.2.0b25}/queue_sdk/queues/base_queue.py +0 -0
  19. {sf_queue_sdk-0.2.0b24 → sf_queue_sdk-0.2.0b25}/queue_sdk/queues/pdf_to_image_queue.py +0 -0
  20. {sf_queue_sdk-0.2.0b24 → sf_queue_sdk-0.2.0b25}/queue_sdk/queues/recommendation_queue.py +0 -0
  21. {sf_queue_sdk-0.2.0b24 → sf_queue_sdk-0.2.0b25}/queue_sdk/queues/tool_assignment_queue.py +0 -0
  22. {sf_queue_sdk-0.2.0b24 → sf_queue_sdk-0.2.0b25}/queue_sdk/queues/topic_assignment_queue.py +0 -0
  23. {sf_queue_sdk-0.2.0b24 → sf_queue_sdk-0.2.0b25}/queue_sdk/redis_client.py +0 -0
  24. {sf_queue_sdk-0.2.0b24 → sf_queue_sdk-0.2.0b25}/queue_sdk/sanitize.py +0 -0
@@ -1,3 +1,11 @@
1
+ Metadata-Version: 2.4
2
+ Name: sf-queue-sdk
3
+ Version: 0.2.0b25
4
+ Summary: Python SDK for sf-queue - Redis-based queue system
5
+ Requires-Python: >=3.11
6
+ Requires-Dist: redis>=5.0.0
7
+ Description-Content-Type: text/markdown
8
+
1
9
  # sf-queue-sdk
2
10
 
3
11
  Python SDK for sf-queue. Enqueues emails via Redis Streams with optional blocking confirmation from the Go consumer service.
@@ -142,6 +150,8 @@ print(result.error) # error message if all failed
142
150
  | `button` | `{"text": str, "href": str}` | No | Call-to-action button |
143
151
  | `reply_to` | `str` | No | Reply-to email address |
144
152
  | `image` | `{"src": str, "alt"?: str, "width"?: int, "height"?: int}` | No | Image in email body |
153
+ | `service` | `str` | No | Service name for routing (e.g. `"sparkles"`). Routes to service-specific credentials, from address, and template. Defaults to the base config when omitted. |
154
+ | `template` | `str` | No | Template name override (e.g. `"sparkles"`). Overrides the service's default template. Falls back to `"studyfetch"` when omitted. |
145
155
 
146
156
  ## Optional Fields
147
157
 
@@ -162,6 +172,31 @@ client.email.send(
162
172
  )
163
173
  ```
164
174
 
175
+ ## Multi-Service Routing
176
+
177
+ Use `service` to route emails through a different service's credentials and branding. The consumer resolves the service name to its configured Resend API key, from address, and default template. Use `template` to override the template for a specific email.
178
+
179
+ ```python
180
+ # Send via a different service's email account and template
181
+ client.email.send(
182
+ to="user@example.com",
183
+ preview="Welcome!",
184
+ subject="Welcome!",
185
+ paragraphs=["Welcome to the platform!"],
186
+ service="sparkles",
187
+ )
188
+
189
+ # Override the template for a specific email
190
+ client.email.send(
191
+ to="user@example.com",
192
+ preview="Welcome!",
193
+ subject="Welcome!",
194
+ paragraphs=["Welcome to the platform!"],
195
+ service="sparkles",
196
+ template="sparkles",
197
+ )
198
+ ```
199
+
165
200
  ## Migrating from sendEmail / sendBatchEmail
166
201
 
167
202
  The SDK is a drop-in replacement. Field names match the existing functions:
@@ -1,11 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: sf-queue-sdk
3
- Version: 0.2.0b24
4
- Summary: Python SDK for sf-queue - Redis-based queue system
5
- Requires-Python: >=3.11
6
- Requires-Dist: redis>=5.0.0
7
- Description-Content-Type: text/markdown
8
-
9
1
  # sf-queue-sdk
10
2
 
11
3
  Python SDK for sf-queue. Enqueues emails via Redis Streams with optional blocking confirmation from the Go consumer service.
@@ -150,6 +142,8 @@ print(result.error) # error message if all failed
150
142
  | `button` | `{"text": str, "href": str}` | No | Call-to-action button |
151
143
  | `reply_to` | `str` | No | Reply-to email address |
152
144
  | `image` | `{"src": str, "alt"?: str, "width"?: int, "height"?: int}` | No | Image in email body |
145
+ | `service` | `str` | No | Service name for routing (e.g. `"sparkles"`). Routes to service-specific credentials, from address, and template. Defaults to the base config when omitted. |
146
+ | `template` | `str` | No | Template name override (e.g. `"sparkles"`). Overrides the service's default template. Falls back to `"studyfetch"` when omitted. |
153
147
 
154
148
  ## Optional Fields
155
149
 
@@ -170,6 +164,31 @@ client.email.send(
170
164
  )
171
165
  ```
172
166
 
167
+ ## Multi-Service Routing
168
+
169
+ Use `service` to route emails through a different service's credentials and branding. The consumer resolves the service name to its configured Resend API key, from address, and default template. Use `template` to override the template for a specific email.
170
+
171
+ ```python
172
+ # Send via a different service's email account and template
173
+ client.email.send(
174
+ to="user@example.com",
175
+ preview="Welcome!",
176
+ subject="Welcome!",
177
+ paragraphs=["Welcome to the platform!"],
178
+ service="sparkles",
179
+ )
180
+
181
+ # Override the template for a specific email
182
+ client.email.send(
183
+ to="user@example.com",
184
+ preview="Welcome!",
185
+ subject="Welcome!",
186
+ paragraphs=["Welcome to the platform!"],
187
+ service="sparkles",
188
+ template="sparkles",
189
+ )
190
+ ```
191
+
173
192
  ## Migrating from sendEmail / sendBatchEmail
174
193
 
175
194
  The SDK is a drop-in replacement. Field names match the existing functions:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sf-queue-sdk"
3
- version = "0.2.0b24"
3
+ version = "0.2.0b25"
4
4
  description = "Python SDK for sf-queue - Redis-based queue system"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -1,6 +1,6 @@
1
1
  """sf-queue Python SDK - Redis-based queue system."""
2
2
 
3
- __version__ = "0.2.0b24"
3
+ __version__ = "0.2.0b25"
4
4
 
5
5
  from queue_sdk.client import QueueClient
6
6
  from queue_sdk.query import QueryClient
@@ -2,7 +2,7 @@
2
2
  # Generated by the protocol buffer compiler. DO NOT EDIT!
3
3
  # NO CHECKED-IN PROTOBUF GENCODE
4
4
  # source: queue/email/v1/email.proto
5
- # Protobuf Python Version: 6.33.5
5
+ # Protobuf Python Version: 7.34.0
6
6
  """Generated protocol buffer code."""
7
7
  from google.protobuf import descriptor as _descriptor
8
8
  from google.protobuf import descriptor_pool as _descriptor_pool
@@ -11,9 +11,9 @@ from google.protobuf import symbol_database as _symbol_database
11
11
  from google.protobuf.internal import builder as _builder
12
12
  _runtime_version.ValidateProtobufRuntimeVersion(
13
13
  _runtime_version.Domain.PUBLIC,
14
- 6,
15
- 33,
16
- 5,
14
+ 7,
15
+ 34,
16
+ 0,
17
17
  '',
18
18
  'queue/email/v1/email.proto'
19
19
  )
@@ -24,7 +24,7 @@ _sym_db = _symbol_database.Default()
24
24
 
25
25
 
26
26
 
27
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1aqueue/email/v1/email.proto\x12\x0equeue.email.v1\"5\n\x0b\x45mailButton\x12\x12\n\x04text\x18\x01 \x01(\tR\x04text\x12\x12\n\x04href\x18\x02 \x01(\tR\x04href\"^\n\nEmailImage\x12\x10\n\x03src\x18\x01 \x01(\tR\x03src\x12\x10\n\x03\x61lt\x18\x02 \x01(\tR\x03\x61lt\x12\x14\n\x05width\x18\x03 \x01(\x05R\x05width\x12\x16\n\x06height\x18\x04 \x01(\x05R\x06height\"\xf4\x01\n\x0c\x45mailRequest\x12\x0e\n\x02to\x18\x01 \x01(\tR\x02to\x12\x18\n\x07preview\x18\x02 \x01(\tR\x07preview\x12\x18\n\x07subject\x18\x03 \x01(\tR\x07subject\x12\x1e\n\nparagraphs\x18\x04 \x03(\tR\nparagraphs\x12\x33\n\x06\x62utton\x18\x05 \x01(\x0b\x32\x1b.queue.email.v1.EmailButtonR\x06\x62utton\x12\x19\n\x08reply_to\x18\x06 \x01(\tR\x07replyTo\x12\x30\n\x05image\x18\x07 \x01(\x0b\x32\x1a.queue.email.v1.EmailImageR\x05image\"\xf9\x01\n\x11\x42\x61tchEmailRequest\x12\x0e\n\x02to\x18\x01 \x03(\tR\x02to\x12\x18\n\x07preview\x18\x02 \x01(\tR\x07preview\x12\x18\n\x07subject\x18\x03 \x01(\tR\x07subject\x12\x1e\n\nparagraphs\x18\x04 \x03(\tR\nparagraphs\x12\x33\n\x06\x62utton\x18\x05 \x01(\x0b\x32\x1b.queue.email.v1.EmailButtonR\x06\x62utton\x12\x19\n\x08reply_to\x18\x06 \x01(\tR\x07replyTo\x12\x30\n\x05image\x18\x07 \x01(\x0b\x32\x1a.queue.email.v1.EmailImageR\x05image\"^\n\rEmailResponse\x12\x18\n\x07success\x18\x01 \x01(\x08R\x07success\x12\x1d\n\nmessage_id\x18\x02 \x01(\tR\tmessageId\x12\x14\n\x05\x65rror\x18\x03 \x01(\tR\x05\x65rrorBLZJgithub.com/StudyFetch/sf-queue/packages/go/proto-go/queue/email/v1;emailv1b\x06proto3')
27
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1aqueue/email/v1/email.proto\x12\x0equeue.email.v1\"5\n\x0b\x45mailButton\x12\x12\n\x04text\x18\x01 \x01(\tR\x04text\x12\x12\n\x04href\x18\x02 \x01(\tR\x04href\"^\n\nEmailImage\x12\x10\n\x03src\x18\x01 \x01(\tR\x03src\x12\x10\n\x03\x61lt\x18\x02 \x01(\tR\x03\x61lt\x12\x14\n\x05width\x18\x03 \x01(\x05R\x05width\x12\x16\n\x06height\x18\x04 \x01(\x05R\x06height\"\xaa\x02\n\x0c\x45mailRequest\x12\x0e\n\x02to\x18\x01 \x01(\tR\x02to\x12\x18\n\x07preview\x18\x02 \x01(\tR\x07preview\x12\x18\n\x07subject\x18\x03 \x01(\tR\x07subject\x12\x1e\n\nparagraphs\x18\x04 \x03(\tR\nparagraphs\x12\x33\n\x06\x62utton\x18\x05 \x01(\x0b\x32\x1b.queue.email.v1.EmailButtonR\x06\x62utton\x12\x19\n\x08reply_to\x18\x06 \x01(\tR\x07replyTo\x12\x30\n\x05image\x18\x07 \x01(\x0b\x32\x1a.queue.email.v1.EmailImageR\x05image\x12\x18\n\x07service\x18\x08 \x01(\tR\x07service\x12\x1a\n\x08template\x18\t \x01(\tR\x08template\"\xaf\x02\n\x11\x42\x61tchEmailRequest\x12\x0e\n\x02to\x18\x01 \x03(\tR\x02to\x12\x18\n\x07preview\x18\x02 \x01(\tR\x07preview\x12\x18\n\x07subject\x18\x03 \x01(\tR\x07subject\x12\x1e\n\nparagraphs\x18\x04 \x03(\tR\nparagraphs\x12\x33\n\x06\x62utton\x18\x05 \x01(\x0b\x32\x1b.queue.email.v1.EmailButtonR\x06\x62utton\x12\x19\n\x08reply_to\x18\x06 \x01(\tR\x07replyTo\x12\x30\n\x05image\x18\x07 \x01(\x0b\x32\x1a.queue.email.v1.EmailImageR\x05image\x12\x18\n\x07service\x18\x08 \x01(\tR\x07service\x12\x1a\n\x08template\x18\t \x01(\tR\x08template\"^\n\rEmailResponse\x12\x18\n\x07success\x18\x01 \x01(\x08R\x07success\x12\x1d\n\nmessage_id\x18\x02 \x01(\tR\tmessageId\x12\x14\n\x05\x65rror\x18\x03 \x01(\tR\x05\x65rrorBLZJgithub.com/StudyFetch/sf-queue/packages/go/proto-go/queue/email/v1;emailv1b\x06proto3')
28
28
 
29
29
  _globals = globals()
30
30
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -37,9 +37,9 @@ if not _descriptor._USE_C_DESCRIPTORS:
37
37
  _globals['_EMAILIMAGE']._serialized_start=101
38
38
  _globals['_EMAILIMAGE']._serialized_end=195
39
39
  _globals['_EMAILREQUEST']._serialized_start=198
40
- _globals['_EMAILREQUEST']._serialized_end=442
41
- _globals['_BATCHEMAILREQUEST']._serialized_start=445
42
- _globals['_BATCHEMAILREQUEST']._serialized_end=694
43
- _globals['_EMAILRESPONSE']._serialized_start=696
44
- _globals['_EMAILRESPONSE']._serialized_end=790
40
+ _globals['_EMAILREQUEST']._serialized_end=496
41
+ _globals['_BATCHEMAILREQUEST']._serialized_start=499
42
+ _globals['_BATCHEMAILREQUEST']._serialized_end=802
43
+ _globals['_EMAILRESPONSE']._serialized_start=804
44
+ _globals['_EMAILRESPONSE']._serialized_end=898
45
45
  # @@protoc_insertion_point(module_scope)
@@ -27,7 +27,7 @@ class EmailImage(_message.Message):
27
27
  def __init__(self, src: _Optional[str] = ..., alt: _Optional[str] = ..., width: _Optional[int] = ..., height: _Optional[int] = ...) -> None: ...
28
28
 
29
29
  class EmailRequest(_message.Message):
30
- __slots__ = ("to", "preview", "subject", "paragraphs", "button", "reply_to", "image")
30
+ __slots__ = ("to", "preview", "subject", "paragraphs", "button", "reply_to", "image", "service", "template")
31
31
  TO_FIELD_NUMBER: _ClassVar[int]
32
32
  PREVIEW_FIELD_NUMBER: _ClassVar[int]
33
33
  SUBJECT_FIELD_NUMBER: _ClassVar[int]
@@ -35,6 +35,8 @@ class EmailRequest(_message.Message):
35
35
  BUTTON_FIELD_NUMBER: _ClassVar[int]
36
36
  REPLY_TO_FIELD_NUMBER: _ClassVar[int]
37
37
  IMAGE_FIELD_NUMBER: _ClassVar[int]
38
+ SERVICE_FIELD_NUMBER: _ClassVar[int]
39
+ TEMPLATE_FIELD_NUMBER: _ClassVar[int]
38
40
  to: str
39
41
  preview: str
40
42
  subject: str
@@ -42,10 +44,12 @@ class EmailRequest(_message.Message):
42
44
  button: EmailButton
43
45
  reply_to: str
44
46
  image: EmailImage
45
- def __init__(self, to: _Optional[str] = ..., preview: _Optional[str] = ..., subject: _Optional[str] = ..., paragraphs: _Optional[_Iterable[str]] = ..., button: _Optional[_Union[EmailButton, _Mapping]] = ..., reply_to: _Optional[str] = ..., image: _Optional[_Union[EmailImage, _Mapping]] = ...) -> None: ...
47
+ service: str
48
+ template: str
49
+ def __init__(self, to: _Optional[str] = ..., preview: _Optional[str] = ..., subject: _Optional[str] = ..., paragraphs: _Optional[_Iterable[str]] = ..., button: _Optional[_Union[EmailButton, _Mapping]] = ..., reply_to: _Optional[str] = ..., image: _Optional[_Union[EmailImage, _Mapping]] = ..., service: _Optional[str] = ..., template: _Optional[str] = ...) -> None: ...
46
50
 
47
51
  class BatchEmailRequest(_message.Message):
48
- __slots__ = ("to", "preview", "subject", "paragraphs", "button", "reply_to", "image")
52
+ __slots__ = ("to", "preview", "subject", "paragraphs", "button", "reply_to", "image", "service", "template")
49
53
  TO_FIELD_NUMBER: _ClassVar[int]
50
54
  PREVIEW_FIELD_NUMBER: _ClassVar[int]
51
55
  SUBJECT_FIELD_NUMBER: _ClassVar[int]
@@ -53,6 +57,8 @@ class BatchEmailRequest(_message.Message):
53
57
  BUTTON_FIELD_NUMBER: _ClassVar[int]
54
58
  REPLY_TO_FIELD_NUMBER: _ClassVar[int]
55
59
  IMAGE_FIELD_NUMBER: _ClassVar[int]
60
+ SERVICE_FIELD_NUMBER: _ClassVar[int]
61
+ TEMPLATE_FIELD_NUMBER: _ClassVar[int]
56
62
  to: _containers.RepeatedScalarFieldContainer[str]
57
63
  preview: str
58
64
  subject: str
@@ -60,7 +66,9 @@ class BatchEmailRequest(_message.Message):
60
66
  button: EmailButton
61
67
  reply_to: str
62
68
  image: EmailImage
63
- def __init__(self, to: _Optional[_Iterable[str]] = ..., preview: _Optional[str] = ..., subject: _Optional[str] = ..., paragraphs: _Optional[_Iterable[str]] = ..., button: _Optional[_Union[EmailButton, _Mapping]] = ..., reply_to: _Optional[str] = ..., image: _Optional[_Union[EmailImage, _Mapping]] = ...) -> None: ...
69
+ service: str
70
+ template: str
71
+ def __init__(self, to: _Optional[_Iterable[str]] = ..., preview: _Optional[str] = ..., subject: _Optional[str] = ..., paragraphs: _Optional[_Iterable[str]] = ..., button: _Optional[_Union[EmailButton, _Mapping]] = ..., reply_to: _Optional[str] = ..., image: _Optional[_Union[EmailImage, _Mapping]] = ..., service: _Optional[str] = ..., template: _Optional[str] = ...) -> None: ...
64
72
 
65
73
  class EmailResponse(_message.Message):
66
74
  __slots__ = ("success", "message_id", "error")
@@ -2,7 +2,7 @@
2
2
  # Generated by the protocol buffer compiler. DO NOT EDIT!
3
3
  # NO CHECKED-IN PROTOBUF GENCODE
4
4
  # source: queue/tool_assignment/v1/tool_assignment.proto
5
- # Protobuf Python Version: 6.33.5
5
+ # Protobuf Python Version: 7.34.0
6
6
  """Generated protocol buffer code."""
7
7
  from google.protobuf import descriptor as _descriptor
8
8
  from google.protobuf import descriptor_pool as _descriptor_pool
@@ -11,9 +11,9 @@ from google.protobuf import symbol_database as _symbol_database
11
11
  from google.protobuf.internal import builder as _builder
12
12
  _runtime_version.ValidateProtobufRuntimeVersion(
13
13
  _runtime_version.Domain.PUBLIC,
14
- 6,
15
- 33,
16
- 5,
14
+ 7,
15
+ 34,
16
+ 0,
17
17
  '',
18
18
  'queue/tool_assignment/v1/tool_assignment.proto'
19
19
  )
@@ -2,7 +2,7 @@
2
2
  # Generated by the protocol buffer compiler. DO NOT EDIT!
3
3
  # NO CHECKED-IN PROTOBUF GENCODE
4
4
  # source: queue/topic_assignment/v1/topic_assignment.proto
5
- # Protobuf Python Version: 6.33.5
5
+ # Protobuf Python Version: 7.34.0
6
6
  """Generated protocol buffer code."""
7
7
  from google.protobuf import descriptor as _descriptor
8
8
  from google.protobuf import descriptor_pool as _descriptor_pool
@@ -11,9 +11,9 @@ from google.protobuf import symbol_database as _symbol_database
11
11
  from google.protobuf.internal import builder as _builder
12
12
  _runtime_version.ValidateProtobufRuntimeVersion(
13
13
  _runtime_version.Domain.PUBLIC,
14
- 6,
15
- 33,
16
- 5,
14
+ 7,
15
+ 34,
16
+ 0,
17
17
  '',
18
18
  'queue/topic_assignment/v1/topic_assignment.proto'
19
19
  )
@@ -28,9 +28,13 @@ class EmailQueue(BaseQueue):
28
28
  button: Optional[dict[str, str]] = None,
29
29
  reply_to: Optional[str] = None,
30
30
  image: Optional[dict[str, Any]] = None,
31
+ service: Optional[str] = None,
32
+ template: Optional[str] = None,
31
33
  ) -> SendResult:
32
34
  """Enqueue an email for processing (fire and forget)."""
33
- payload = self._build_payload(to, preview, subject, paragraphs, button, reply_to, image)
35
+ payload = self._build_payload(
36
+ to, preview, subject, paragraphs, button, reply_to, image, service, template
37
+ )
34
38
  message_id = self._enqueue(payload)
35
39
  return SendResult(message_id=message_id)
36
40
 
@@ -44,9 +48,13 @@ class EmailQueue(BaseQueue):
44
48
  reply_to: Optional[str] = None,
45
49
  image: Optional[dict[str, Any]] = None,
46
50
  timeout: Optional[int] = None,
51
+ service: Optional[str] = None,
52
+ template: Optional[str] = None,
47
53
  ) -> EmailResponse:
48
54
  """Enqueue an email and wait for processing confirmation."""
49
- payload = self._build_payload(to, preview, subject, paragraphs, button, reply_to, image)
55
+ payload = self._build_payload(
56
+ to, preview, subject, paragraphs, button, reply_to, image, service, template
57
+ )
50
58
  return self._enqueue_and_wait(payload, timeout)
51
59
 
52
60
  def send_batch(
@@ -58,10 +66,14 @@ class EmailQueue(BaseQueue):
58
66
  button: Optional[dict[str, str]] = None,
59
67
  reply_to: Optional[str] = None,
60
68
  image: Optional[dict[str, Any]] = None,
69
+ service: Optional[str] = None,
70
+ template: Optional[str] = None,
61
71
  ) -> SendResult:
62
72
  """Enqueue a batch email for processing (fire and forget)."""
63
73
  self._validate_batch(to)
64
- payload = self._build_batch_payload(to, preview, subject, paragraphs, button, reply_to, image)
74
+ payload = self._build_batch_payload(
75
+ to, preview, subject, paragraphs, button, reply_to, image, service, template
76
+ )
65
77
  message_id = self._enqueue(payload)
66
78
  return SendResult(message_id=message_id)
67
79
 
@@ -75,10 +87,14 @@ class EmailQueue(BaseQueue):
75
87
  reply_to: Optional[str] = None,
76
88
  image: Optional[dict[str, Any]] = None,
77
89
  timeout: Optional[int] = None,
90
+ service: Optional[str] = None,
91
+ template: Optional[str] = None,
78
92
  ) -> BatchEmailResponse:
79
93
  """Enqueue a batch email and wait for processing confirmation."""
80
94
  self._validate_batch(to)
81
- payload = self._build_batch_payload(to, preview, subject, paragraphs, button, reply_to, image)
95
+ payload = self._build_batch_payload(
96
+ to, preview, subject, paragraphs, button, reply_to, image, service, template
97
+ )
82
98
  response = self._enqueue_and_wait(payload, timeout)
83
99
 
84
100
  return BatchEmailResponse(
@@ -100,6 +116,8 @@ class EmailQueue(BaseQueue):
100
116
  button: Optional[dict[str, str]],
101
117
  reply_to: Optional[str],
102
118
  image: Optional[dict[str, Any]],
119
+ service: Optional[str] = None,
120
+ template: Optional[str] = None,
103
121
  ) -> dict[str, Any]:
104
122
  """Build and sanitize the email payload."""
105
123
  payload: dict[str, Any] = {
@@ -126,6 +144,12 @@ class EmailQueue(BaseQueue):
126
144
  "height": image.get("height"),
127
145
  }
128
146
 
147
+ if service:
148
+ payload["service"] = service
149
+
150
+ if template:
151
+ payload["template"] = template
152
+
129
153
  return payload
130
154
 
131
155
  def _build_batch_payload(
@@ -137,16 +161,20 @@ class EmailQueue(BaseQueue):
137
161
  button: Optional[dict[str, str]],
138
162
  reply_to: Optional[str],
139
163
  image: Optional[dict[str, Any]],
164
+ service: Optional[str] = None,
165
+ template: Optional[str] = None,
140
166
  ) -> dict[str, Any]:
141
167
  """Build and sanitize the batch email payload."""
142
168
  payload = self._build_payload(
143
- to="", # not used for batch
169
+ to="",
144
170
  preview=preview,
145
171
  subject=subject,
146
172
  paragraphs=paragraphs,
147
173
  button=button,
148
174
  reply_to=reply_to,
149
175
  image=image,
176
+ service=service,
177
+ template=template,
150
178
  )
151
179
  payload["to"] = to
152
180
  payload["batch"] = True
@@ -42,6 +42,8 @@ class EmailData:
42
42
  button: Optional[EmailButton] = None
43
43
  reply_to: Optional[str] = None
44
44
  image: Optional[EmailImage] = None
45
+ service: Optional[str] = None
46
+ template: Optional[str] = None
45
47
 
46
48
 
47
49
  @dataclass
@@ -55,6 +57,8 @@ class BatchEmailData:
55
57
  button: Optional[EmailButton] = None
56
58
  reply_to: Optional[str] = None
57
59
  image: Optional[EmailImage] = None
60
+ service: Optional[str] = None
61
+ template: Optional[str] = None
58
62
 
59
63
 
60
64
  @dataclass