@stacksjs/email 0.69.2 → 0.70.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/dist/base.d.ts +130 -0
- package/dist/email.d.ts +2 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +15330 -1
- package/dist/mailgun.d.ts +141 -0
- package/dist/mailtrap.d.ts +131 -0
- package/dist/sendgrid.d.ts +146 -0
- package/dist/ses.d.ts +80 -0
- package/dist/template.d.ts +5 -5
- package/package.json +6 -6
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import type { EmailAddress, EmailMessage, EmailResult, RenderOptions } from '@stacksjs/types';
|
|
2
|
+
|
|
3
|
+
export declare class MailgunDriver extends BaseEmailDriver {
|
|
4
|
+
public name = 'mailgun'
|
|
5
|
+
private apiKey: string
|
|
6
|
+
private domain: string
|
|
7
|
+
private endpoint: string
|
|
8
|
+
|
|
9
|
+
constructor() {
|
|
10
|
+
super()
|
|
11
|
+
this.apiKey = config.services.mailgun?.apiKey ?? ''
|
|
12
|
+
this.domain = config.services.mailgun?.domain ?? ''
|
|
13
|
+
this.endpoint = config.services.mailgun?.endpoint ?? 'api.mailgun.net'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public async send(message: EmailMessage, options?: RenderOptions): Promise<EmailResult> {
|
|
17
|
+
const logContext = {
|
|
18
|
+
provider: this.name,
|
|
19
|
+
to: message.to,
|
|
20
|
+
subject: message.subject,
|
|
21
|
+
domain: this.domain,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
log.info('Sending email via Mailgun...', logContext)
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
this.validateMessage(message)
|
|
28
|
+
|
|
29
|
+
let htmlContent: string | undefined
|
|
30
|
+
if (message.template) {
|
|
31
|
+
const templ = await template(message.template, options)
|
|
32
|
+
if (templ && 'html' in templ) {
|
|
33
|
+
htmlContent = templ.html
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const formData = new FormData()
|
|
38
|
+
formData.append('from', this.formatMailgunAddress(message.from))
|
|
39
|
+
|
|
40
|
+
this.formatMailgunAddresses(message.to).forEach(to => formData.append('to', to))
|
|
41
|
+
|
|
42
|
+
if (message.cc)
|
|
43
|
+
this.formatMailgunAddresses(message.cc).forEach(cc => formData.append('cc', cc))
|
|
44
|
+
|
|
45
|
+
if (message.bcc)
|
|
46
|
+
this.formatMailgunAddresses(message.bcc).forEach(bcc => formData.append('bcc', bcc))
|
|
47
|
+
|
|
48
|
+
formData.append('subject', message.subject)
|
|
49
|
+
|
|
50
|
+
if (htmlContent) {
|
|
51
|
+
formData.append('html', htmlContent)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (message.text)
|
|
55
|
+
formData.append('text', message.text)
|
|
56
|
+
|
|
57
|
+
if (message.attachments) {
|
|
58
|
+
message.attachments.forEach((attachment) => {
|
|
59
|
+
const content = typeof attachment.content === 'string'
|
|
60
|
+
? attachment.content
|
|
61
|
+
: this.arrayBufferToBase64(attachment.content)
|
|
62
|
+
|
|
63
|
+
formData.append('attachment', new Blob([content], { type: attachment.contentType }), attachment.filename)
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const response = await this.sendWithRetry(formData)
|
|
68
|
+
return this.handleSuccess(message, response.id)
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
return this.handleError(error, message)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private formatMailgunAddress(address: EmailAddress): string {
|
|
76
|
+
return address.name ? `${address.name} <${address.address}>` : address.address
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private formatMailgunAddresses(addresses: string | string[] | EmailAddress[] | undefined): string[] {
|
|
80
|
+
if (!addresses)
|
|
81
|
+
return []
|
|
82
|
+
|
|
83
|
+
if (typeof addresses === 'string')
|
|
84
|
+
return [addresses]
|
|
85
|
+
|
|
86
|
+
return addresses.map((addr) => {
|
|
87
|
+
if (typeof addr === 'string')
|
|
88
|
+
return addr
|
|
89
|
+
return addr.name ? `${addr.name} <${addr.address}>` : addr.address
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private arrayBufferToBase64(buffer: Uint8Array): string {
|
|
94
|
+
let binary = ''
|
|
95
|
+
const bytes = new Uint8Array(buffer)
|
|
96
|
+
const len = bytes.byteLength
|
|
97
|
+
|
|
98
|
+
for (let i = 0; i < len; i++) {
|
|
99
|
+
binary += String.fromCharCode(bytes[i])
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return typeof btoa === 'function'
|
|
103
|
+
? btoa(binary)
|
|
104
|
+
: Buffer.from(binary).toString('base64')
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private async sendWithRetry(formData: FormData, attempt = 1): Promise<any> {
|
|
108
|
+
const url = `https:
|
|
109
|
+
const auth = Buffer.from(`api:${this.apiKey}`).toString('base64')
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
const response = await fetch(url, {
|
|
113
|
+
method: 'POST',
|
|
114
|
+
headers: {
|
|
115
|
+
Authorization: `Basic ${auth}`,
|
|
116
|
+
},
|
|
117
|
+
body: formData,
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
if (!response.ok) {
|
|
121
|
+
const errorData = await response.json()
|
|
122
|
+
throw new Error(`Mailgun API error: ${response.status} - ${JSON.stringify(errorData)}`)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const data = await response.json()
|
|
126
|
+
log.info(`[${this.name}] Email sent successfully`, { attempt, messageId: data.id })
|
|
127
|
+
return data
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
if (attempt < (config.services.mailgun?.maxRetries ?? 3)) {
|
|
131
|
+
const retryTimeout = config.services.mailgun?.retryTimeout ?? 1000
|
|
132
|
+
log.warn(`[${this.name}] Email send failed, retrying (${attempt}/${config.services.mailgun?.maxRetries ?? 3})`)
|
|
133
|
+
await new Promise(resolve => setTimeout(resolve, retryTimeout))
|
|
134
|
+
return this.sendWithRetry(formData, attempt + 1)
|
|
135
|
+
}
|
|
136
|
+
throw error
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export default MailgunDriver;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import type { EmailMessage, EmailResult, MailtrapResponse, RenderOptions } from '@stacksjs/types';
|
|
2
|
+
|
|
3
|
+
export declare class MailtrapDriver extends BaseEmailDriver {
|
|
4
|
+
public name = 'mailtrap'
|
|
5
|
+
private host: string
|
|
6
|
+
private token: string
|
|
7
|
+
private inboxId?: number
|
|
8
|
+
|
|
9
|
+
constructor() {
|
|
10
|
+
super()
|
|
11
|
+
this.host = config.services.mailtrap?.host ?? 'https:
|
|
12
|
+
this.token = config.services.mailtrap?.token ?? ''
|
|
13
|
+
this.inboxId = config.services.mailtrap?.inboxId ? Number(config.services.mailtrap.inboxId) : undefined
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public async send(message: EmailMessage, options?: RenderOptions): Promise<EmailResult> {
|
|
17
|
+
const logContext = {
|
|
18
|
+
provider: this.name,
|
|
19
|
+
to: message.to,
|
|
20
|
+
subject: message.subject,
|
|
21
|
+
inboxId: this.inboxId,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
log.info('Sending email via Mailtrap...', logContext)
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
this.validateMessage(message)
|
|
28
|
+
let templ
|
|
29
|
+
if (message.template)
|
|
30
|
+
templ = await template(message.template, options)
|
|
31
|
+
|
|
32
|
+
const mailtrapPayload = {
|
|
33
|
+
from: {
|
|
34
|
+
email: message.from.address || config.email.from?.address,
|
|
35
|
+
...(message.from.name && { name: message.from.name }),
|
|
36
|
+
},
|
|
37
|
+
to: this.formatMailtrapAddresses(message.to),
|
|
38
|
+
...(message.cc && { cc: this.formatMailtrapAddresses(message.cc) }),
|
|
39
|
+
...(message.bcc && { bcc: this.formatMailtrapAddresses(message.bcc) }),
|
|
40
|
+
subject: message.subject,
|
|
41
|
+
...(templ?.html && { html: templ.html }),
|
|
42
|
+
...(message.text && { text: message.text }),
|
|
43
|
+
...(message.attachments && {
|
|
44
|
+
attachments: message.attachments.map(attachment => ({
|
|
45
|
+
filename: attachment.filename,
|
|
46
|
+
content: typeof attachment.content === 'string'
|
|
47
|
+
? attachment.content
|
|
48
|
+
: this.arrayBufferToBase64(attachment.content),
|
|
49
|
+
type: attachment.contentType || 'application/octet-stream',
|
|
50
|
+
})),
|
|
51
|
+
}),
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const response = await this.sendWithRetry(mailtrapPayload)
|
|
55
|
+
return this.handleSuccess(message, response.message_ids?.[0])
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
return this.handleError(error, message)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private formatMailtrapAddresses(addresses: string | string[] | EmailAddress[] | undefined): Array<{ email: string, name?: string }> {
|
|
63
|
+
if (!addresses)
|
|
64
|
+
return []
|
|
65
|
+
|
|
66
|
+
if (typeof addresses === 'string') {
|
|
67
|
+
return [{ email: addresses }]
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return addresses.map((addr) => {
|
|
71
|
+
if (typeof addr === 'string')
|
|
72
|
+
return { email: addr }
|
|
73
|
+
return { email: addr.address, ...(addr.name && { name: addr.name }) }
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private arrayBufferToBase64(buffer: Uint8Array): string {
|
|
78
|
+
let binary = ''
|
|
79
|
+
const bytes = new Uint8Array(buffer)
|
|
80
|
+
const len = bytes.byteLength
|
|
81
|
+
|
|
82
|
+
for (let i = 0; i < len; i++) {
|
|
83
|
+
binary += String.fromCharCode(bytes[i])
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return typeof btoa === 'function'
|
|
87
|
+
? btoa(binary)
|
|
88
|
+
: Buffer.from(binary).toString('base64')
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
private async sendWithRetry(payload: any, attempt = 1): Promise<any> {
|
|
92
|
+
if (!this.inboxId) {
|
|
93
|
+
throw new Error('Mailtrap inbox ID is required but not provided. Please set MAILTRAP_INBOX_ID in your environment variables.')
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const endpoint = `${this.host}/${this.inboxId}`
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
const response = await fetch(endpoint, {
|
|
100
|
+
method: 'POST',
|
|
101
|
+
headers: {
|
|
102
|
+
'Authorization': `Bearer ${this.token}`,
|
|
103
|
+
'Content-Type': 'application/json',
|
|
104
|
+
},
|
|
105
|
+
body: JSON.stringify(payload),
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
if (!response.ok) {
|
|
109
|
+
const errorData = await response.json()
|
|
110
|
+
throw new Error(`Mailtrap API error: ${response.status} - ${JSON.stringify(errorData)}`)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const data: MailtrapResponse = await (response.json() as Promise<MailtrapResponse>)
|
|
114
|
+
|
|
115
|
+
log.info(`[${this.name}] Email sent successfully`, { attempt, messageId: data.message_ids?.[0] })
|
|
116
|
+
return data
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
if (attempt < (config.services.mailtrap?.maxRetries ?? 3)) {
|
|
120
|
+
const retryTimeout = config.services.mailtrap?.retryTimeout ?? 1000
|
|
121
|
+
log.warn(`[${this.name}] Email send failed, retrying (${attempt}/${config.services.mailtrap?.maxRetries ?? 3})`)
|
|
122
|
+
await new Promise(resolve => setTimeout(resolve, retryTimeout))
|
|
123
|
+
|
|
124
|
+
return this.sendWithRetry(payload, attempt + 1)
|
|
125
|
+
}
|
|
126
|
+
throw error
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export default MailtrapDriver;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import type { EmailMessage, EmailResult, RenderOptions } from '@stacksjs/types';
|
|
2
|
+
|
|
3
|
+
export declare class SendGridDriver extends BaseEmailDriver {
|
|
4
|
+
public name = 'sendgrid'
|
|
5
|
+
private apiKey: string
|
|
6
|
+
|
|
7
|
+
constructor() {
|
|
8
|
+
super()
|
|
9
|
+
this.apiKey = config.services.sendgrid?.apiKey ?? ''
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
public async send(message: EmailMessage, options?: RenderOptions): Promise<EmailResult> {
|
|
13
|
+
const logContext = {
|
|
14
|
+
provider: this.name,
|
|
15
|
+
to: message.to,
|
|
16
|
+
subject: message.subject,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
log.info('Sending email via SendGrid...', logContext)
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
this.validateMessage(message)
|
|
23
|
+
|
|
24
|
+
let htmlContent: string | undefined
|
|
25
|
+
if (message.template) {
|
|
26
|
+
const templ = await template(message.template, options)
|
|
27
|
+
if (templ && 'html' in templ) {
|
|
28
|
+
htmlContent = templ.html
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const content = []
|
|
33
|
+
|
|
34
|
+
if (htmlContent) {
|
|
35
|
+
content.push({
|
|
36
|
+
type: 'text/html',
|
|
37
|
+
value: htmlContent,
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (message.text) {
|
|
42
|
+
content.push({
|
|
43
|
+
type: 'text/plain',
|
|
44
|
+
value: message.text,
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (content.length === 0) {
|
|
49
|
+
throw new Error('Email must have either HTML or text content')
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const sendgridPayload = {
|
|
53
|
+
personalizations: [
|
|
54
|
+
{
|
|
55
|
+
to: this.formatSendGridAddresses(message.to),
|
|
56
|
+
...(message.cc && { cc: this.formatSendGridAddresses(message.cc) }),
|
|
57
|
+
...(message.bcc && { bcc: this.formatSendGridAddresses(message.bcc) }),
|
|
58
|
+
subject: message.subject,
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
from: {
|
|
62
|
+
email: message.from.address || config.email.from?.address,
|
|
63
|
+
...(message.from.name && { name: message.from.name }),
|
|
64
|
+
},
|
|
65
|
+
content,
|
|
66
|
+
...(message.attachments && {
|
|
67
|
+
attachments: message.attachments.map(attachment => ({
|
|
68
|
+
filename: attachment.filename,
|
|
69
|
+
content: typeof attachment.content === 'string'
|
|
70
|
+
? attachment.content
|
|
71
|
+
: this.arrayBufferToBase64(attachment.content),
|
|
72
|
+
type: attachment.contentType,
|
|
73
|
+
disposition: 'attachment',
|
|
74
|
+
})),
|
|
75
|
+
}),
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const response = await this.sendWithRetry(sendgridPayload)
|
|
79
|
+
return this.handleSuccess(message, response.headers?.['x-message-id'])
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
return this.handleError(error, message)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private formatSendGridAddresses(addresses: string | string[] | EmailAddress[] | undefined): Array<{ email: string, name?: string }> {
|
|
87
|
+
if (!addresses)
|
|
88
|
+
return []
|
|
89
|
+
|
|
90
|
+
if (typeof addresses === 'string') {
|
|
91
|
+
return [{ email: addresses }]
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return addresses.map((addr) => {
|
|
95
|
+
if (typeof addr === 'string')
|
|
96
|
+
return { email: addr }
|
|
97
|
+
return { email: addr.address, ...(addr.name && { name: addr.name }) }
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private arrayBufferToBase64(buffer: Uint8Array): string {
|
|
102
|
+
let binary = ''
|
|
103
|
+
const bytes = new Uint8Array(buffer)
|
|
104
|
+
const len = bytes.byteLength
|
|
105
|
+
|
|
106
|
+
for (let i = 0; i < len; i++) {
|
|
107
|
+
binary += String.fromCharCode(bytes[i])
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return typeof btoa === 'function'
|
|
111
|
+
? btoa(binary)
|
|
112
|
+
: Buffer.from(binary).toString('base64')
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private async sendWithRetry(payload: any, attempt = 1): Promise<any> {
|
|
116
|
+
try {
|
|
117
|
+
const response = await fetch('https:
|
|
118
|
+
method: 'POST',
|
|
119
|
+
headers: {
|
|
120
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
121
|
+
'Content-Type': 'application/json',
|
|
122
|
+
},
|
|
123
|
+
body: JSON.stringify(payload),
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
if (!response.ok) {
|
|
127
|
+
const errorData = await response.json()
|
|
128
|
+
throw new Error(`SendGrid API error: ${response.status} - ${JSON.stringify(errorData)}`)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
log.info(`[${this.name}] Email sent successfully`, { attempt })
|
|
132
|
+
return response
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
if (attempt < (config.services.sendgrid?.maxRetries ?? 3)) {
|
|
136
|
+
const retryTimeout = config.services.sendgrid?.retryTimeout ?? 1000
|
|
137
|
+
log.warn(`[${this.name}] Email send failed, retrying (${attempt}/${config.services.sendgrid?.maxRetries ?? 3})`)
|
|
138
|
+
await new Promise(resolve => setTimeout(resolve, retryTimeout))
|
|
139
|
+
return this.sendWithRetry(payload, attempt + 1)
|
|
140
|
+
}
|
|
141
|
+
throw error
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export default SendGridDriver;
|
package/dist/ses.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { EmailMessage, EmailResult, RenderOptions } from '@stacksjs/types';
|
|
2
|
+
|
|
3
|
+
export declare class SESDriver extends BaseEmailDriver {
|
|
4
|
+
public name = 'ses'
|
|
5
|
+
private client: SES
|
|
6
|
+
|
|
7
|
+
constructor() {
|
|
8
|
+
super()
|
|
9
|
+
|
|
10
|
+
const credentials = {
|
|
11
|
+
accessKeyId: config.services.ses?.credentials?.accessKeyId ?? '',
|
|
12
|
+
secretAccessKey: config.services.ses?.credentials?.secretAccessKey ?? '',
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
this.client = new SES({
|
|
16
|
+
region: config.services.ses?.region || 'us-east-1',
|
|
17
|
+
credentials,
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public async send(message: EmailMessage, options?: RenderOptions): Promise<EmailResult> {
|
|
22
|
+
try {
|
|
23
|
+
this.validateMessage(message)
|
|
24
|
+
|
|
25
|
+
let htmlContent: string | undefined
|
|
26
|
+
if (message.template) {
|
|
27
|
+
const templ = await template(message.template, options)
|
|
28
|
+
if (templ && 'html' in templ) {
|
|
29
|
+
htmlContent = templ.html
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const messageBody: any = {}
|
|
34
|
+
|
|
35
|
+
if (htmlContent) {
|
|
36
|
+
messageBody.Html = {
|
|
37
|
+
Charset: config.email.charset || 'UTF-8',
|
|
38
|
+
Data: htmlContent,
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (message.text) {
|
|
43
|
+
messageBody.Text = {
|
|
44
|
+
Charset: config.email.charset || 'UTF-8',
|
|
45
|
+
Data: message.text,
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (Object.keys(messageBody).length === 0) {
|
|
50
|
+
throw new Error('Email must have either HTML or text content')
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const params = {
|
|
54
|
+
Source: message.from?.address || config.email.from?.address,
|
|
55
|
+
|
|
56
|
+
Destination: {
|
|
57
|
+
ToAddresses: this.formatAddresses(message.to),
|
|
58
|
+
CcAddresses: this.formatAddresses(message.cc),
|
|
59
|
+
BccAddresses: this.formatAddresses(message.bcc),
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
Message: {
|
|
63
|
+
Body: messageBody,
|
|
64
|
+
Subject: {
|
|
65
|
+
Charset: config.email.charset || 'UTF-8',
|
|
66
|
+
Data: message.subject,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const response = await this.client.send(new SendEmailCommand(params))
|
|
72
|
+
return this.handleSuccess(message, response.MessageId)
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
return this.handleError(error, message)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export default SESDriver;
|
package/dist/template.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RenderOptions } from '@stacksjs/types';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
declare interface HtmlResult {
|
|
4
|
+
html: string
|
|
5
|
+
text: string
|
|
6
6
|
}
|
|
7
|
-
export declare function template(path: string, options?: RenderOptions): Promise<
|
|
7
|
+
export declare function template(path: string, options?: RenderOptions): Promise<HtmlResult>;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacksjs/email",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.70.0",
|
|
5
5
|
"description": "The Stacks Email integration. Painlessly create & manage your inboxes, templates, and send emails.",
|
|
6
6
|
"author": "Chris Breuer",
|
|
7
7
|
"contributors": ["Chris Breuer <chris@stacksjs.org>"],
|
|
@@ -35,11 +35,11 @@
|
|
|
35
35
|
"prepublishOnly": "bun run build"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@stacksjs/cli": "0.
|
|
39
|
-
"@stacksjs/config": "0.
|
|
40
|
-
"@stacksjs/development": "0.
|
|
41
|
-
"@stacksjs/error-handling": "0.
|
|
42
|
-
"@stacksjs/types": "0.
|
|
38
|
+
"@stacksjs/cli": "0.70.0",
|
|
39
|
+
"@stacksjs/config": "0.70.0",
|
|
40
|
+
"@stacksjs/development": "0.70.0",
|
|
41
|
+
"@stacksjs/error-handling": "0.70.0",
|
|
42
|
+
"@stacksjs/types": "0.70.0",
|
|
43
43
|
"aws-sdk": "^2.1692.0",
|
|
44
44
|
"vue-email": "^0.8.11"
|
|
45
45
|
}
|