cypress-mailisk 3.2.1 → 3.3.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.
package/README.md CHANGED
@@ -5,7 +5,7 @@ Mailisk is an end-to-end email and SMS testing platform. It allows you to receiv
5
5
  - Get a unique subdomain and unlimited email addresses for free.
6
6
  - Easily automate E2E password reset and account verification by catching emails.
7
7
  - Receive SMS messages and automate SMS tests.
8
- - Virtual SMTP and SMS support to test without 3rd party clients.
8
+ - Outbound email and virtual SMS support to test without 3rd party clients.
9
9
 
10
10
  ## Get started
11
11
 
@@ -148,6 +148,71 @@ cy.mailiskDownloadAttachment('attachment-id').then((buffer) => {
148
148
  });
149
149
  ```
150
150
 
151
+ ### Outbound email
152
+
153
+ These commands create, queue, and inspect outbound email delivery through the Mailisk API.
154
+
155
+ ```js
156
+ cy.mailiskSendEmail('mynamespace', {
157
+ from: {
158
+ email: 'support@mynamespace.mailisk.net',
159
+ name: 'Support',
160
+ },
161
+ to: ['verified@example.com'],
162
+ subject: 'Hello from Mailisk',
163
+ text: 'This is the plain text body.',
164
+ html: '<p>This is the HTML body.</p>',
165
+ }).then((outboundEmail) => {
166
+ expect(outboundEmail.status).to.equal('queued');
167
+
168
+ cy.mailiskGetOutboundEmail(outboundEmail.id).then((detail) => {
169
+ expect(detail.recipients).to.not.be.empty;
170
+ });
171
+ });
172
+ ```
173
+
174
+ Messages sent only to the same namespace do not consume outbound usage because they are counted as inbound email when delivered.
175
+
176
+ Send an outbound email with an attachment:
177
+
178
+ ```js
179
+ cy.fixture('report.txt', 'base64').then((contentBase64) => {
180
+ cy.mailiskSendEmail('mynamespace', {
181
+ to: ['verified@example.com'],
182
+ subject: 'Report',
183
+ text: 'Attached.',
184
+ attachments: [
185
+ {
186
+ filename: 'report.txt',
187
+ content_type: 'application/octet-stream',
188
+ content_base64: contentBase64,
189
+ },
190
+ ],
191
+ });
192
+ });
193
+ ```
194
+
195
+ Reply to an inbound email returned by `cy.mailiskSearchInbox()`:
196
+
197
+ ```js
198
+ cy.mailiskSearchInbox('mynamespace', {
199
+ to_addr_prefix: 'support@mynamespace.mailisk.net',
200
+ }).then((response) => {
201
+ cy.mailiskReplyToEmail(response.data[0].id, {
202
+ text: 'Thanks, we received your message.',
203
+ });
204
+ });
205
+ ```
206
+
207
+ Forward an inbound email:
208
+
209
+ ```js
210
+ cy.mailiskForwardEmail('inbound-email-id', {
211
+ to: ['verified@example.com'],
212
+ text: 'Forwarding this along.',
213
+ });
214
+ ```
215
+
151
216
  ### cy.mailiskSearchSms
152
217
 
153
218
  This is the main command to interact with Mailisk SMS, it wraps the [Search SMS](/api-reference/search-sms) endpoint. Use a phone number that is registered to your account.
@@ -214,7 +279,7 @@ cy.mailiskListSmsNumbers().then((response) => {
214
279
 
215
280
  ### TOTP authenticator devices
216
281
 
217
- These commands manage saved Mailisk Authenticator devices and generate OTP codes through the Mailisk API. Use an organisation API key for these endpoints.
282
+ These commands manage saved Mailisk Authenticator devices and generate OTP codes through the Mailisk API.
218
283
 
219
284
  ```js
220
285
  cy.mailiskDeviceList({ issuer: 'GitHub', username: 'qa@example.com' }).then((response) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cypress-mailisk",
3
- "version": "3.2.1",
3
+ "version": "3.3.0",
4
4
  "description": "Mailisk library for Cypress",
5
5
  "keywords": [
6
6
  "mailisk",
@@ -219,6 +219,227 @@ export interface SendVirtualSmsParams {
219
219
  body: string;
220
220
  }
221
221
 
222
+ export type OutboundEmailType = 'new' | 'reply' | 'forward';
223
+
224
+ export type OutboundEmailStatus = 'queued' | 'sending' | 'sent' | 'failed';
225
+
226
+ export type OutboundEmailRecipientType = 'to' | 'cc' | 'bcc';
227
+
228
+ export type OutboundEmailRecipientDeliveryStatus =
229
+ | 'pending'
230
+ | 'accepted'
231
+ | 'queued'
232
+ | 'sent'
233
+ | 'delayed'
234
+ | 'deferred'
235
+ | 'delivered'
236
+ | 'bounced'
237
+ | 'expired'
238
+ | 'complained'
239
+ | 'unsubscribed'
240
+ | 'suppressed'
241
+ | 'rejected'
242
+ | 'failed'
243
+ | 'cancelled';
244
+
245
+ export type OutboundEmailEventType =
246
+ | 'accepted'
247
+ | 'queued'
248
+ | 'sent'
249
+ | 'failed'
250
+ | 'rejected'
251
+ | 'delayed'
252
+ | 'deferred'
253
+ | 'delivered'
254
+ | 'bounced'
255
+ | 'expired'
256
+ | 'complained'
257
+ | 'unsubscribed'
258
+ | 'suppressed'
259
+ | 'cancelled'
260
+ | 'opened'
261
+ | 'clicked';
262
+
263
+ export type OutboundEmailAttachmentDisposition = 'attachment' | 'inline';
264
+
265
+ export interface OutboundEmailAddress {
266
+ /** Email address */
267
+ email: string;
268
+ /** Display name, if one is specified */
269
+ name?: string;
270
+ }
271
+
272
+ export interface OutboundEmailAttachment {
273
+ /** Filename of the attachment */
274
+ filename: string;
275
+ /** MIME content type */
276
+ content_type: string;
277
+ /** Base64 encoded attachment content */
278
+ content_base64: string;
279
+ /** Content-ID for inline attachments */
280
+ content_id?: string;
281
+ /** Attachment disposition */
282
+ disposition?: OutboundEmailAttachmentDisposition;
283
+ }
284
+
285
+ export interface SendEmailParams {
286
+ /** Optional sender override. Must belong to the requested namespace. */
287
+ from?: OutboundEmailAddress;
288
+ /** Optional Reply-To address */
289
+ reply_to?: OutboundEmailAddress;
290
+ /** Primary recipients */
291
+ to?: string[];
292
+ /** Carbon-copied recipients */
293
+ cc?: string[];
294
+ /** Blind carbon-copied recipients */
295
+ bcc?: string[];
296
+ /** Email subject */
297
+ subject: string;
298
+ /** HTML message body */
299
+ html?: string;
300
+ /** Plain text message body */
301
+ text?: string;
302
+ /** Attachments to include */
303
+ attachments?: OutboundEmailAttachment[];
304
+ }
305
+
306
+ export interface ReplyToEmailParams {
307
+ /** Optional sender override. Must belong to the source email namespace. */
308
+ from?: OutboundEmailAddress;
309
+ /** Carbon-copied recipients */
310
+ cc?: string[];
311
+ /** Blind carbon-copied recipients */
312
+ bcc?: string[];
313
+ /** Optional subject. Defaults to Re: original subject. */
314
+ subject?: string;
315
+ /** HTML reply body */
316
+ html?: string;
317
+ /** Plain text reply body */
318
+ text?: string;
319
+ /** Attachments to include */
320
+ attachments?: OutboundEmailAttachment[];
321
+ }
322
+
323
+ export interface ForwardEmailParams {
324
+ /** Optional sender override. Must belong to the source email namespace. */
325
+ from?: OutboundEmailAddress;
326
+ /** Primary recipients */
327
+ to: string[];
328
+ /** Carbon-copied recipients */
329
+ cc?: string[];
330
+ /** Blind carbon-copied recipients */
331
+ bcc?: string[];
332
+ /** Optional subject. Defaults to Fwd: original subject. */
333
+ subject?: string;
334
+ /** Optional HTML body to prepend before the forwarded message */
335
+ html?: string;
336
+ /** Optional plain text body to prepend before the forwarded message */
337
+ text?: string;
338
+ }
339
+
340
+ export interface OutboundEmailResponse {
341
+ id: string;
342
+ organisation_id: string;
343
+ type: OutboundEmailType;
344
+ status: OutboundEmailStatus;
345
+ from: OutboundEmailAddress;
346
+ reply_to?: OutboundEmailAddress;
347
+ subject: string;
348
+ recipient_count: number;
349
+ attachment_count: number;
350
+ message_id: string;
351
+ provider?: string;
352
+ provider_message_id?: string;
353
+ failure_reason?: string;
354
+ queued_at: string;
355
+ sending_at?: string;
356
+ sent_at?: string;
357
+ failed_at?: string;
358
+ created_at: string;
359
+ updated_at: string;
360
+ }
361
+
362
+ export interface OutboundEmailDeliverySummary {
363
+ pending: number;
364
+ accepted: number;
365
+ queued: number;
366
+ sent: number;
367
+ delayed: number;
368
+ deferred: number;
369
+ delivered: number;
370
+ bounced: number;
371
+ expired: number;
372
+ complained: number;
373
+ unsubscribed: number;
374
+ suppressed: number;
375
+ rejected: number;
376
+ failed: number;
377
+ cancelled: number;
378
+ }
379
+
380
+ export interface OutboundEmailRecipient {
381
+ id: string;
382
+ type: OutboundEmailRecipientType;
383
+ email: string;
384
+ name?: string;
385
+ delivery_status: OutboundEmailRecipientDeliveryStatus;
386
+ last_event_type?: string;
387
+ last_event_at?: string;
388
+ accepted_at?: string;
389
+ queued_at?: string;
390
+ sent_at?: string;
391
+ delayed_at?: string;
392
+ deferred_at?: string;
393
+ delivered_at?: string;
394
+ bounced_at?: string;
395
+ expired_at?: string;
396
+ complained_at?: string;
397
+ unsubscribed_at?: string;
398
+ suppressed_at?: string;
399
+ rejected_at?: string;
400
+ failed_at?: string;
401
+ cancelled_at?: string;
402
+ last_smtp_code?: string;
403
+ last_enhanced_status_code?: string;
404
+ last_smtp_response?: string;
405
+ attempt_count: number;
406
+ bounce_type?: string;
407
+ bounce_subtype?: string;
408
+ bounce_classification?: string;
409
+ complaint_feedback_type?: string;
410
+ }
411
+
412
+ export interface OutboundEmailEventRecipient {
413
+ id: string;
414
+ outbound_email_recipient_id?: string;
415
+ email: string;
416
+ smtp_code?: string;
417
+ enhanced_status_code?: string;
418
+ smtp_response?: string;
419
+ diagnostic_code?: string;
420
+ action?: string;
421
+ attempt_count?: number;
422
+ bounce_classification?: string;
423
+ }
424
+
425
+ export interface OutboundEmailEvent {
426
+ id: string;
427
+ provider: string;
428
+ provider_message_id?: string;
429
+ provider_event_id?: string;
430
+ event_type: OutboundEmailEventType;
431
+ event_subtype?: string;
432
+ occurred_at: string;
433
+ recipients: OutboundEmailEventRecipient[];
434
+ created_at: string;
435
+ }
436
+
437
+ export interface OutboundEmailDetailResponse extends OutboundEmailResponse {
438
+ delivery_summary: OutboundEmailDeliverySummary;
439
+ recipients: OutboundEmailRecipient[];
440
+ events: OutboundEmailEvent[];
441
+ }
442
+
222
443
  export type TotpAlgorithm = 'SHA1' | 'SHA256' | 'SHA512';
223
444
 
224
445
  export type KnownTotpDeviceSource = 'shared_secret' | 'custom' | 'base32_secret_key' | 'otpauth_url';
@@ -400,6 +621,70 @@ declare global {
400
621
  options?: Partial<Cypress.RequestOptions>,
401
622
  ): Cypress.Chainable<Buffer>;
402
623
 
624
+ mailiskSendEmail(
625
+ /**
626
+ * Namespace to send from.
627
+ */
628
+ namespace: string,
629
+ /**
630
+ * Outbound email input.
631
+ */
632
+ input: SendEmailParams,
633
+ /**
634
+ * Request options.
635
+ *
636
+ * See https://docs.cypress.io/api/commands/request#Arguments
637
+ */
638
+ options?: Partial<Cypress.RequestOptions>,
639
+ ): Cypress.Chainable<OutboundEmailResponse>;
640
+
641
+ mailiskGetOutboundEmail(
642
+ /**
643
+ * Outbound email ID returned by mailiskSendEmail, mailiskReplyToEmail, or mailiskForwardEmail.
644
+ */
645
+ outboundEmailId: string,
646
+ /**
647
+ * Request options.
648
+ *
649
+ * See https://docs.cypress.io/api/commands/request#Arguments
650
+ */
651
+ options?: Partial<Cypress.RequestOptions>,
652
+ ): Cypress.Chainable<OutboundEmailDetailResponse>;
653
+
654
+ mailiskReplyToEmail(
655
+ /**
656
+ * Inbound email ID returned by mailiskSearchInbox.
657
+ */
658
+ emailId: string,
659
+ /**
660
+ * Reply input.
661
+ */
662
+ input: ReplyToEmailParams,
663
+ /**
664
+ * Request options.
665
+ *
666
+ * See https://docs.cypress.io/api/commands/request#Arguments
667
+ */
668
+ options?: Partial<Cypress.RequestOptions>,
669
+ ): Cypress.Chainable<OutboundEmailResponse>;
670
+
671
+ mailiskForwardEmail(
672
+ /**
673
+ * Inbound email ID returned by mailiskSearchInbox.
674
+ */
675
+ emailId: string,
676
+ /**
677
+ * Forward input.
678
+ */
679
+ input: ForwardEmailParams,
680
+ /**
681
+ * Request options.
682
+ *
683
+ * See https://docs.cypress.io/api/commands/request#Arguments
684
+ */
685
+ options?: Partial<Cypress.RequestOptions>,
686
+ ): Cypress.Chainable<OutboundEmailResponse>;
687
+
403
688
  mailiskSearchSms(
404
689
  /**
405
690
  * The phone number to search.
@@ -8,6 +8,10 @@ class MailiskCommands {
8
8
  'mailiskSearchInbox',
9
9
  'mailiskGetAttachment',
10
10
  'mailiskDownloadAttachment',
11
+ 'mailiskSendEmail',
12
+ 'mailiskGetOutboundEmail',
13
+ 'mailiskReplyToEmail',
14
+ 'mailiskForwardEmail',
11
15
  'mailiskSearchSms',
12
16
  'mailiskListSmsNumbers',
13
17
  'mailiskDeviceList',
@@ -134,6 +138,28 @@ class MailiskCommands {
134
138
  );
135
139
  }
136
140
 
141
+ mailiskSendEmail(namespace, input, options = {}) {
142
+ const urlParams = this._buildUrlParams({ namespace: this._requireNonEmptyString(namespace, 'namespace') });
143
+ return this._withRequest((request) => request.post(`api/emails/send?${urlParams.toString()}`, input, options));
144
+ }
145
+
146
+ mailiskGetOutboundEmail(outboundEmailId, options = {}) {
147
+ const encodedOutboundEmailId = encodeURIComponent(
148
+ this._requireNonEmptyString(outboundEmailId, 'outboundEmailId'),
149
+ );
150
+ return this._withRequest((request) => request.get(`api/emails/outbound/${encodedOutboundEmailId}`, options));
151
+ }
152
+
153
+ mailiskReplyToEmail(emailId, input, options = {}) {
154
+ const encodedEmailId = encodeURIComponent(this._requireNonEmptyString(emailId, 'emailId'));
155
+ return this._withRequest((request) => request.post(`api/emails/${encodedEmailId}/reply`, input, options));
156
+ }
157
+
158
+ mailiskForwardEmail(emailId, input, options = {}) {
159
+ const encodedEmailId = encodeURIComponent(this._requireNonEmptyString(emailId, 'emailId'));
160
+ return this._withRequest((request) => request.post(`api/emails/${encodedEmailId}/forward`, input, options));
161
+ }
162
+
137
163
  _mailiskSearchSmsAction(request, phoneNumber, _options, urlParams, startTime, nextTimeout) {
138
164
  return request
139
165
  .get(`api/sms/${phoneNumber}/messages?${urlParams.toString()}`, { ..._options, timeout: nextTimeout })