@drax/email-back 0.9.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/config/EmailConfig.js +14 -0
- package/dist/factory/EmailServiceFactory.js +46 -0
- package/dist/index.js +4 -0
- package/dist/interfaces/IEmailLayout.js +1 -0
- package/dist/interfaces/ITransportConfig.js +1 -0
- package/dist/services/EmailLayoutService.js +106 -0
- package/dist/services/EmailService.js +58 -0
- package/package.json +42 -0
- package/src/config/EmailConfig.ts +14 -0
- package/src/factory/EmailServiceFactory.ts +56 -0
- package/src/index.ts +18 -0
- package/src/interfaces/IEmailLayout.ts +25 -0
- package/src/interfaces/ITransportConfig.ts +21 -0
- package/src/services/EmailLayoutService.ts +123 -0
- package/src/services/EmailService.ts +81 -0
- package/test/Email.test.ts +83 -0
- package/test/EmailLayout.test.ts +193 -0
- package/test/template.pug +123 -0
- package/tsconfig.json +16 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/types/config/EmailConfig.d.ts +14 -0
- package/types/config/EmailConfig.d.ts.map +1 -0
- package/types/factory/EmailServiceFactory.d.ts +11 -0
- package/types/factory/EmailServiceFactory.d.ts.map +1 -0
- package/types/index.d.ts +8 -0
- package/types/index.d.ts.map +1 -0
- package/types/interfaces/IEmailLayout.d.ts +19 -0
- package/types/interfaces/IEmailLayout.d.ts.map +1 -0
- package/types/interfaces/ITransportConfig.d.ts +19 -0
- package/types/interfaces/ITransportConfig.d.ts.map +1 -0
- package/types/services/EmailLayoutService.d.ts +12 -0
- package/types/services/EmailLayoutService.d.ts.map +1 -0
- package/types/services/EmailService.d.ts +13 -0
- package/types/services/EmailService.d.ts.map +1 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import {describe, test} from "vitest";
|
|
2
|
+
import {EmailLayoutService} from '../src/services/EmailLayoutService.js'
|
|
3
|
+
import {fileURLToPath} from "url";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import {EmailServiceFactory} from "../src/factory/EmailServiceFactory.js";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
let body = `
|
|
9
|
+
<h2 style="font-size: 22px; color: #333333; font-weight: 600; margin: 0 0 10px 0;">Bienvenido a Nuestro Boletín</h2>
|
|
10
|
+
<p style="font-size: 16px; line-height: 1.6; color: #555555; margin: 0 0 15px 0;">Hola, nos complace anunciarte nuestras últimas novedades. En este correo te mantendremos actualizado sobre todos nuestros productos y servicios. Gracias por formar parte de nuestra comunidad.</p>
|
|
11
|
+
<p style="font-size: 16px; line-height: 1.6; color: #555555; margin: 0;">Si tienes alguna duda, no dudes en contactarnos. Estamos aquí para ayudarte.</p>
|
|
12
|
+
`
|
|
13
|
+
|
|
14
|
+
//I Need the absolute path of template.pug file in the same directory as this file with nodejs 20 and type module
|
|
15
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
+
const __dirname = path.dirname(__filename);
|
|
17
|
+
const templatePath = path.join(__dirname, 'template.pug');
|
|
18
|
+
|
|
19
|
+
describe("Email Service", function () {
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
test("Email Send with Preview Logo Title default style", async () => {
|
|
23
|
+
|
|
24
|
+
// modify run configuration: --env-file .env
|
|
25
|
+
|
|
26
|
+
let emailLayoutService = new EmailLayoutService({
|
|
27
|
+
headerCentered: false,
|
|
28
|
+
headerTitle: 'Example',
|
|
29
|
+
headerLogo: 'https://media.sondeosglobal.com/media/files/cincarnato/2023/11/sndlogo-H31daC.png',
|
|
30
|
+
footerCopyright: 'My Company. Todos los derechos reservados.',
|
|
31
|
+
footerContent: '<p>Some Text here.</p>',
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const mail = {
|
|
35
|
+
from: 'from@example.com',
|
|
36
|
+
to: 'to@example.com',
|
|
37
|
+
subject: 'the subject',
|
|
38
|
+
html: emailLayoutService.html(body),
|
|
39
|
+
text: ''
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let emailService = EmailServiceFactory.instance
|
|
43
|
+
|
|
44
|
+
const r = await emailService.sendEmail({
|
|
45
|
+
from: 'ci.sys.virtual@gmail.com',
|
|
46
|
+
to: 'cristian.cdi@gmail.com',
|
|
47
|
+
subject: 'the subject',
|
|
48
|
+
html: emailLayoutService.html(body),
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
console.log("R", r)
|
|
52
|
+
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test("Email send Image", async () => {
|
|
56
|
+
|
|
57
|
+
// modify run configuration: --env-file .env
|
|
58
|
+
|
|
59
|
+
let emailLayoutService = new EmailLayoutService({
|
|
60
|
+
headerCentered: false,
|
|
61
|
+
headerImage: 'https://media.sondeosglobal.com/media/files/cincarnato/2025/1/bannerdrax-rsDnbj.png',
|
|
62
|
+
headerImageStyle: 'width: 800px; display: block; margin: 0 auto;',
|
|
63
|
+
footerCopyright: 'My Company. Todos los derechos reservados.',
|
|
64
|
+
footerContent: '<p>Some Text here.</p>',
|
|
65
|
+
footerUnsubscribe: '<a href="/">Unsuscribe</a>'
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
let emailService = EmailServiceFactory.instance
|
|
70
|
+
|
|
71
|
+
const r = await emailService.sendEmail({
|
|
72
|
+
from: 'ci.sys.virtual@gmail.com',
|
|
73
|
+
to: 'cristian.cdi@gmail.com',
|
|
74
|
+
subject: 'the subject',
|
|
75
|
+
html: emailLayoutService.html(body),
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
console.log("R", r)
|
|
79
|
+
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
})
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import {describe, test} from "vitest";
|
|
2
|
+
import {EmailLayoutService} from '../src/services/EmailLayoutService.js'
|
|
3
|
+
import {EmailService} from '../src/services/EmailService.js'
|
|
4
|
+
import previewEmail from 'preview-email';
|
|
5
|
+
import {fileURLToPath} from "url";
|
|
6
|
+
import path from "path";
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
let body = `
|
|
10
|
+
<h2 style="font-size: 22px; color: #333333; font-weight: 600; margin: 0 0 10px 0;">Bienvenido a Nuestro Boletín</h2>
|
|
11
|
+
<p style="font-size: 16px; line-height: 1.6; color: #555555; margin: 0 0 15px 0;">Hola, nos complace anunciarte nuestras últimas novedades. En este correo te mantendremos actualizado sobre todos nuestros productos y servicios. Gracias por formar parte de nuestra comunidad.</p>
|
|
12
|
+
<p style="font-size: 16px; line-height: 1.6; color: #555555; margin: 0;">Si tienes alguna duda, no dudes en contactarnos. Estamos aquí para ayudarte.</p>
|
|
13
|
+
`
|
|
14
|
+
|
|
15
|
+
//I Need the absolute path of template.pug file in the same directory as this file with nodejs 20 and type module
|
|
16
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
17
|
+
const __dirname = path.dirname(__filename);
|
|
18
|
+
const templatePath = path.join(__dirname, 'template.pug');
|
|
19
|
+
|
|
20
|
+
describe("Email Layout", function () {
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
test("Email Layout Preview Image", async () => {
|
|
24
|
+
|
|
25
|
+
let emailLayoutService = new EmailLayoutService({
|
|
26
|
+
headerCentered: true,
|
|
27
|
+
headerImage: 'https://media.sondeosglobal.com/media/files/cincarnato/2025/1/bannerdrax-rsDnbj.png',
|
|
28
|
+
headerImageStyle: 'height: 170px; width: auto; display: block; margin: auto;',
|
|
29
|
+
footerCopyright: 'My Company. Todos los derechos reservados.',
|
|
30
|
+
footerUnsubscribe: '<a>Unsuscribe</a>'
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
const mail = {
|
|
34
|
+
from: 'from@example.com',
|
|
35
|
+
to: 'to@example.com',
|
|
36
|
+
subject: 'the subject',
|
|
37
|
+
html: emailLayoutService.html(body),
|
|
38
|
+
text: '',
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const r = await previewEmail(mail,{ template: templatePath})
|
|
43
|
+
|
|
44
|
+
console.log("R", r)
|
|
45
|
+
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
test("Email Layout Preview Logo Title", async () => {
|
|
49
|
+
|
|
50
|
+
let emailLayoutService = new EmailLayoutService({
|
|
51
|
+
maxWidth: '900px',
|
|
52
|
+
headerCentered: false,
|
|
53
|
+
headerBgColor: 'red',
|
|
54
|
+
headerTitle: 'Example',
|
|
55
|
+
headerTitleStyle: 'color: yellow; font-size: 28px; margin: 0; font-weight: 700;',
|
|
56
|
+
headerLogo: 'https://media.sondeosglobal.com/media/files/cincarnato/2023/11/sndlogo-H31daC.png',
|
|
57
|
+
headerLogoStyle: 'height: 70px; width: auto; display: block; margin: auto;',
|
|
58
|
+
footerBgColor: 'cyan',
|
|
59
|
+
footerCopyright: 'My Company. Todos los derechos reservados.',
|
|
60
|
+
footerContent: '<p>Some Text here.</p>',
|
|
61
|
+
footerUnsubscribe: '<a href="/">Unsuscribe</a>'
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
const mail = {
|
|
66
|
+
from: 'from@example.com',
|
|
67
|
+
to: 'to@example.com',
|
|
68
|
+
subject: 'the subject',
|
|
69
|
+
html: emailLayoutService.html(body),
|
|
70
|
+
text: ''
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const r = await previewEmail(mail,{ template: templatePath})
|
|
74
|
+
|
|
75
|
+
console.log("R", r)
|
|
76
|
+
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
test("Email Layout Preview Logo Title default style", async () => {
|
|
80
|
+
|
|
81
|
+
let emailLayoutService = new EmailLayoutService({
|
|
82
|
+
headerCentered: false,
|
|
83
|
+
headerTitle: 'Example',
|
|
84
|
+
headerLogo: 'https://media.sondeosglobal.com/media/files/cincarnato/2023/11/sndlogo-H31daC.png',
|
|
85
|
+
footerCopyright: 'My Company. Todos los derechos reservados.',
|
|
86
|
+
footerContent: '<p>Some Text here.</p>',
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
const mail = {
|
|
90
|
+
from: 'from@example.com',
|
|
91
|
+
to: 'to@example.com',
|
|
92
|
+
subject: 'the subject',
|
|
93
|
+
html: emailLayoutService.html(body),
|
|
94
|
+
text: ''
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const r = await previewEmail(mail,{ template: templatePath})
|
|
98
|
+
|
|
99
|
+
console.log("R", r)
|
|
100
|
+
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
test("Email Layout Preview Logo", async () => {
|
|
104
|
+
|
|
105
|
+
let emailLayoutService = new EmailLayoutService({
|
|
106
|
+
maxWidth: '900px',
|
|
107
|
+
headerCentered: false,
|
|
108
|
+
headerBgColor: 'red',
|
|
109
|
+
headerColor: 'yellow',
|
|
110
|
+
headerLogo: 'https://media.sondeosglobal.com/media/files/cincarnato/2023/11/sndlogo-H31daC.png',
|
|
111
|
+
footerBgColor: 'cyan',
|
|
112
|
+
footerCopyright: 'My Company. Todos los derechos reservados.',
|
|
113
|
+
footerContent: '<p>Some Text here.</p>',
|
|
114
|
+
footerUnsubscribe: '<a href="/">Unsuscribe</a>'
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
const mail = {
|
|
119
|
+
from: 'from@example.com',
|
|
120
|
+
to: 'to@example.com',
|
|
121
|
+
subject: 'the subject',
|
|
122
|
+
html: emailLayoutService.html(body),
|
|
123
|
+
text: ''
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const r = await previewEmail(mail,{ template: templatePath})
|
|
127
|
+
|
|
128
|
+
console.log("R", r)
|
|
129
|
+
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
test("Email Layout Preview Title", async () => {
|
|
133
|
+
|
|
134
|
+
let emailLayoutService = new EmailLayoutService({
|
|
135
|
+
maxWidth: '900px',
|
|
136
|
+
headerCentered: false,
|
|
137
|
+
headerBgColor: 'red',
|
|
138
|
+
headerColor: 'yellow',
|
|
139
|
+
headerTitle: 'Example',
|
|
140
|
+
footerBgColor: 'cyan',
|
|
141
|
+
footerCopyright: 'My Company. Todos los derechos reservados.',
|
|
142
|
+
footerContent: '<p>Some Text here.</p>',
|
|
143
|
+
footerUnsubscribe: '<a href="/">Unsuscribe</a>'
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
const mail = {
|
|
148
|
+
from: 'from@example.com',
|
|
149
|
+
to: 'to@example.com',
|
|
150
|
+
subject: 'the subject',
|
|
151
|
+
html: emailLayoutService.html(body),
|
|
152
|
+
text: ''
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const r = await previewEmail(mail,{ template: templatePath})
|
|
156
|
+
|
|
157
|
+
console.log("R", r)
|
|
158
|
+
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
test("Email Layout send", async () => {
|
|
162
|
+
|
|
163
|
+
let emailLayoutService = new EmailLayoutService({
|
|
164
|
+
headerCentered: false,
|
|
165
|
+
headerImage: 'https://media.sondeosglobal.com/media/files/cincarnato/2025/1/banner-lZEeQe.png',
|
|
166
|
+
headerTitle: 'Example',
|
|
167
|
+
headerLogo: 'https://media.sondeosglobal.com/media/files/cincarnato/2023/11/sndlogo-H31daC.png',
|
|
168
|
+
footerCopyright: 'My Company. Todos los derechos reservados.',
|
|
169
|
+
footerContent: '<p>Some Text here.</p>',
|
|
170
|
+
footerUnsubscribe: '<a href="/">Unsuscribe</a>'
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
let emailService = new EmailService('gmail', {
|
|
175
|
+
auth: {
|
|
176
|
+
user: process.env.EMAIL_AUTH_USERNAME,
|
|
177
|
+
pass: process.env.EMAIL_AUTH_PASSWORD
|
|
178
|
+
}
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
const r = await emailService.sendEmail({
|
|
182
|
+
from: 'ci.sys.virtual@gmail.com',
|
|
183
|
+
to: 'cristian.cdi@gmail.com',
|
|
184
|
+
subject: 'the subject',
|
|
185
|
+
html: emailLayoutService.html(body),
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
console.log("R", r)
|
|
189
|
+
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
})
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
doctype html
|
|
2
|
+
html
|
|
3
|
+
head
|
|
4
|
+
meta(charset="utf-8")
|
|
5
|
+
meta(http-equiv="x-ua-compatible", content="ie=edge")
|
|
6
|
+
if subject
|
|
7
|
+
title= subject
|
|
8
|
+
meta(name="viewport", content="width=device-width, initial-scale=1")
|
|
9
|
+
style(type='text/css').
|
|
10
|
+
iframe {
|
|
11
|
+
border: 0;
|
|
12
|
+
height: 100%;
|
|
13
|
+
width: 100%;
|
|
14
|
+
min-height: 800px;
|
|
15
|
+
max-width: 100%;
|
|
16
|
+
display: block;
|
|
17
|
+
}
|
|
18
|
+
.preview-email-tabs {
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-wrap: wrap;
|
|
21
|
+
max-width: 100%;
|
|
22
|
+
border: 1px solid black;
|
|
23
|
+
background: #ffffff;
|
|
24
|
+
}
|
|
25
|
+
.preview-email-tabs input[type="radio"] {
|
|
26
|
+
display: none;
|
|
27
|
+
}
|
|
28
|
+
.preview-email-tabs label {
|
|
29
|
+
padding: 1rem;
|
|
30
|
+
background: #ffffff;
|
|
31
|
+
font-weight: bold;
|
|
32
|
+
cursor: pointer;
|
|
33
|
+
}
|
|
34
|
+
.preview-email-tabs .preview-email-tab {
|
|
35
|
+
width: 100%;
|
|
36
|
+
background: #fff;
|
|
37
|
+
order: 1;
|
|
38
|
+
display: none;
|
|
39
|
+
}
|
|
40
|
+
.preview-email-tabs input[type='radio']:checked + label + .preview-email-tab {
|
|
41
|
+
display: block;
|
|
42
|
+
}
|
|
43
|
+
.preview-email-tabs input[type="radio"]:checked + label {
|
|
44
|
+
background: #fff;
|
|
45
|
+
}
|
|
46
|
+
body
|
|
47
|
+
table
|
|
48
|
+
if base64
|
|
49
|
+
tr
|
|
50
|
+
td(colspan=2, style='text-align:right;'): button(type='button', onclick='downloadRawEmail()') Download Original
|
|
51
|
+
script.
|
|
52
|
+
function downloadRawEmail() {
|
|
53
|
+
var link = document.createElement('a');
|
|
54
|
+
link.href = "data:message/rfc822;base64,#{base64}";
|
|
55
|
+
link.download = "#{messageId ? messageId.replace('<', '').replace('>', '').split('@')[0] : Date.now()}.eml";
|
|
56
|
+
link.click();
|
|
57
|
+
}
|
|
58
|
+
each headerLine, i in headerLines
|
|
59
|
+
- const index = headerLine.line.indexOf(': ')
|
|
60
|
+
- const value = headerLine.line.slice(index + 2)
|
|
61
|
+
- const header = headers.get(headerLine.key)
|
|
62
|
+
tr
|
|
63
|
+
td
|
|
64
|
+
strong= headerLine.line.slice(0, index)
|
|
65
|
+
td
|
|
66
|
+
if header
|
|
67
|
+
case headerLine.key
|
|
68
|
+
when 'content-type'
|
|
69
|
+
//- TODO: header.params[key]
|
|
70
|
+
= header.value || header || value
|
|
71
|
+
when 'content-disposition'
|
|
72
|
+
when 'dkim-signature'
|
|
73
|
+
//- TODO: header.params[key]
|
|
74
|
+
= value
|
|
75
|
+
when 'subject'
|
|
76
|
+
when 'references'
|
|
77
|
+
when 'message-id'
|
|
78
|
+
when 'in-reply-to'
|
|
79
|
+
when 'priority'
|
|
80
|
+
when 'x-priority'
|
|
81
|
+
when 'x-msmail-priority'
|
|
82
|
+
when 'importance'
|
|
83
|
+
= header.value || header || value
|
|
84
|
+
when 'from'
|
|
85
|
+
when 'to'
|
|
86
|
+
when 'cc'
|
|
87
|
+
when 'bcc'
|
|
88
|
+
when 'sender'
|
|
89
|
+
when 'reply-to'
|
|
90
|
+
when 'delivered-to'
|
|
91
|
+
when 'return-path'
|
|
92
|
+
if header.html
|
|
93
|
+
!= header.html
|
|
94
|
+
else
|
|
95
|
+
= header.value || header || value
|
|
96
|
+
default
|
|
97
|
+
//- when 'date'
|
|
98
|
+
= header.value || header || value
|
|
99
|
+
else
|
|
100
|
+
= value
|
|
101
|
+
if attachments && attachments.length > 0
|
|
102
|
+
tr
|
|
103
|
+
td: strong Attachments
|
|
104
|
+
td
|
|
105
|
+
ul
|
|
106
|
+
each a in attachments
|
|
107
|
+
li
|
|
108
|
+
a(href=`data:${a.contentType};base64,${a.content.toString('base64')}`, download=a.filename, target='_blank')
|
|
109
|
+
if a.filename
|
|
110
|
+
code= a.filename
|
|
111
|
+
else
|
|
112
|
+
code= 'Unnamed file'
|
|
113
|
+
.preview-email-tabs
|
|
114
|
+
if html
|
|
115
|
+
input(type='radio', name='preview_email', checked)#tab-html
|
|
116
|
+
label(for='tab-html') HTML
|
|
117
|
+
.preview-email-tab
|
|
118
|
+
iframe(sandbox='allow-popups', referrerpolicy='no-referrer', seamless='seamless', srcdoc=`<base target='_top'>${html}`)#html
|
|
119
|
+
if text
|
|
120
|
+
input(type='radio', name='preview_email', checked=!html)#tab-text
|
|
121
|
+
label(for='tab-text') Plain text
|
|
122
|
+
.preview-email-tab
|
|
123
|
+
iframe(sandbox='allow-popups', referrerpolicy='no-referrer', seamless='seamless', srcdoc=`<pre>${text}</pre>`)#text
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"rootDir": "src",
|
|
5
|
+
"outDir": "dist",
|
|
6
|
+
"declarationDir": "./types",
|
|
7
|
+
},
|
|
8
|
+
"exclude": ["test", "types","dist"],
|
|
9
|
+
"ts-node": {
|
|
10
|
+
"esm": true
|
|
11
|
+
},
|
|
12
|
+
"tsc-alias": {
|
|
13
|
+
"resolveFullPaths": true,
|
|
14
|
+
"verbose": false
|
|
15
|
+
}
|
|
16
|
+
}
|