]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/lib/emailer.ts
Fix notification icon position
[github/Chocobozzz/PeerTube.git] / server / lib / emailer.ts
CommitLineData
ecb4e35f
C
1import { createTransport, Transporter } from 'nodemailer'
2import { isTestInstance } from '../helpers/core-utils'
05e67d62 3import { bunyanLogger, logger } from '../helpers/logger'
ecb4e35f 4import { CONFIG } from '../initializers'
ba75d268
C
5import { UserModel } from '../models/account/user'
6import { VideoModel } from '../models/video/video'
ecb4e35f
C
7import { JobQueue } from './job-queue'
8import { EmailPayload } from './job-queue/handlers/email'
c9d5c64f 9import { readFileSync } from 'fs-extra'
cef534ed
C
10import { VideoCommentModel } from '../models/video/video-comment'
11import { VideoAbuseModel } from '../models/video/video-abuse'
12import { VideoBlacklistModel } from '../models/video/video-blacklist'
ecb4e35f
C
13
14class Emailer {
15
16 private static instance: Emailer
17 private initialized = false
18 private transporter: Transporter
3b3b1820 19 private enabled = false
ecb4e35f
C
20
21 private constructor () {}
22
23 init () {
24 // Already initialized
25 if (this.initialized === true) return
26 this.initialized = true
27
28 if (CONFIG.SMTP.HOSTNAME && CONFIG.SMTP.PORT) {
29 logger.info('Using %s:%s as SMTP server.', CONFIG.SMTP.HOSTNAME, CONFIG.SMTP.PORT)
30
31 let tls
32 if (CONFIG.SMTP.CA_FILE) {
33 tls = {
34 ca: [ readFileSync(CONFIG.SMTP.CA_FILE) ]
35 }
36 }
37
f076daa7
C
38 let auth
39 if (CONFIG.SMTP.USERNAME && CONFIG.SMTP.PASSWORD) {
40 auth = {
41 user: CONFIG.SMTP.USERNAME,
42 pass: CONFIG.SMTP.PASSWORD
43 }
44 }
45
ecb4e35f
C
46 this.transporter = createTransport({
47 host: CONFIG.SMTP.HOSTNAME,
48 port: CONFIG.SMTP.PORT,
49 secure: CONFIG.SMTP.TLS,
05e67d62
C
50 debug: CONFIG.LOG.LEVEL === 'debug',
51 logger: bunyanLogger as any,
bebf2d89 52 ignoreTLS: CONFIG.SMTP.DISABLE_STARTTLS,
ecb4e35f 53 tls,
f076daa7 54 auth
ecb4e35f 55 })
3b3b1820
C
56
57 this.enabled = true
ecb4e35f
C
58 } else {
59 if (!isTestInstance()) {
60 logger.error('Cannot use SMTP server because of lack of configuration. PeerTube will not be able to send mails!')
61 }
62 }
63 }
64
3b3b1820
C
65 isEnabled () {
66 return this.enabled
67 }
68
ecb4e35f
C
69 async checkConnectionOrDie () {
70 if (!this.transporter) return
71
3d3441d6
C
72 logger.info('Testing SMTP server...')
73
ecb4e35f
C
74 try {
75 const success = await this.transporter.verify()
76 if (success !== true) this.dieOnConnectionFailure()
77
78 logger.info('Successfully connected to SMTP server.')
79 } catch (err) {
80 this.dieOnConnectionFailure(err)
81 }
82 }
83
cef534ed
C
84 addNewVideoFromSubscriberNotification (to: string[], video: VideoModel) {
85 const channelName = video.VideoChannel.getDisplayName()
86 const videoUrl = CONFIG.WEBSERVER.URL + video.getWatchStaticPath()
87
ecb4e35f 88 const text = `Hi dear user,\n\n` +
cef534ed
C
89 `Your subscription ${channelName} just published a new video: ${video.name}` +
90 `\n\n` +
91 `You can view it on ${videoUrl} ` +
92 `\n\n` +
ecb4e35f
C
93 `Cheers,\n` +
94 `PeerTube.`
95
96 const emailPayload: EmailPayload = {
cef534ed
C
97 to,
98 subject: channelName + ' just published a new video',
ecb4e35f
C
99 text
100 }
101
102 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
103 }
104
cef534ed
C
105 addNewCommentOnMyVideoNotification (to: string[], comment: VideoCommentModel) {
106 const accountName = comment.Account.getDisplayName()
107 const video = comment.Video
108 const commentUrl = CONFIG.WEBSERVER.URL + comment.getCommentStaticPath()
109
110 const text = `Hi dear user,\n\n` +
111 `A new comment has been posted by ${accountName} on your video ${video.name}` +
112 `\n\n` +
113 `You can view it on ${commentUrl} ` +
114 `\n\n` +
d9eaee39
JM
115 `Cheers,\n` +
116 `PeerTube.`
117
118 const emailPayload: EmailPayload = {
cef534ed
C
119 to,
120 subject: 'New comment on your video ' + video.name,
d9eaee39
JM
121 text
122 }
123
124 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
125 }
126
cef534ed
C
127 async addVideoAbuseModeratorsNotification (to: string[], videoAbuse: VideoAbuseModel) {
128 const videoUrl = CONFIG.WEBSERVER.URL + videoAbuse.Video.getWatchStaticPath()
ba75d268
C
129
130 const text = `Hi,\n\n` +
cef534ed 131 `${CONFIG.WEBSERVER.HOST} received an abuse for the following video ${videoUrl}\n\n` +
ba75d268
C
132 `Cheers,\n` +
133 `PeerTube.`
134
ba75d268
C
135 const emailPayload: EmailPayload = {
136 to,
137 subject: '[PeerTube] Received a video abuse',
138 text
139 }
140
141 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
142 }
143
cef534ed
C
144 async addVideoBlacklistNotification (to: string[], videoBlacklist: VideoBlacklistModel) {
145 const videoName = videoBlacklist.Video.name
146 const videoUrl = CONFIG.WEBSERVER.URL + videoBlacklist.Video.getWatchStaticPath()
26b7305a 147
cef534ed
C
148 const reasonString = videoBlacklist.reason ? ` for the following reason: ${videoBlacklist.reason}` : ''
149 const blockedString = `Your video ${videoName} (${videoUrl} on ${CONFIG.WEBSERVER.HOST} has been blacklisted${reasonString}.`
26b7305a
C
150
151 const text = 'Hi,\n\n' +
152 blockedString +
153 '\n\n' +
154 'Cheers,\n' +
155 `PeerTube.`
156
26b7305a 157 const emailPayload: EmailPayload = {
cef534ed
C
158 to,
159 subject: `[PeerTube] Video ${videoName} blacklisted`,
26b7305a
C
160 text
161 }
162
163 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
164 }
165
cef534ed
C
166 async addVideoUnblacklistNotification (to: string[], video: VideoModel) {
167 const videoUrl = CONFIG.WEBSERVER.URL + video.getWatchStaticPath()
26b7305a
C
168
169 const text = 'Hi,\n\n' +
cef534ed 170 `Your video ${video.name} (${videoUrl}) on ${CONFIG.WEBSERVER.HOST} has been unblacklisted.` +
26b7305a
C
171 '\n\n' +
172 'Cheers,\n' +
173 `PeerTube.`
174
26b7305a 175 const emailPayload: EmailPayload = {
cef534ed 176 to,
26b7305a
C
177 subject: `[PeerTube] Video ${video.name} unblacklisted`,
178 text
179 }
180
181 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
182 }
183
cef534ed
C
184 addForgetPasswordEmailJob (to: string, resetPasswordUrl: string) {
185 const text = `Hi dear user,\n\n` +
186 `It seems you forgot your password on ${CONFIG.WEBSERVER.HOST}! ` +
187 `Please follow this link to reset it: ${resetPasswordUrl}\n\n` +
188 `If you are not the person who initiated this request, please ignore this email.\n\n` +
189 `Cheers,\n` +
190 `PeerTube.`
191
192 const emailPayload: EmailPayload = {
193 to: [ to ],
194 subject: 'Reset your PeerTube password',
195 text
196 }
197
198 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
199 }
200
201 addVerifyEmailJob (to: string, verifyEmailUrl: string) {
202 const text = `Welcome to PeerTube,\n\n` +
203 `To start using PeerTube on ${CONFIG.WEBSERVER.HOST} you must verify your email! ` +
204 `Please follow this link to verify this email belongs to you: ${verifyEmailUrl}\n\n` +
205 `If you are not the person who initiated this request, please ignore this email.\n\n` +
206 `Cheers,\n` +
207 `PeerTube.`
208
209 const emailPayload: EmailPayload = {
210 to: [ to ],
211 subject: 'Verify your PeerTube email',
212 text
213 }
214
215 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
216 }
217
eacb25c4
C
218 addUserBlockJob (user: UserModel, blocked: boolean, reason?: string) {
219 const reasonString = reason ? ` for the following reason: ${reason}` : ''
220 const blockedWord = blocked ? 'blocked' : 'unblocked'
221 const blockedString = `Your account ${user.username} on ${CONFIG.WEBSERVER.HOST} has been ${blockedWord}${reasonString}.`
222
223 const text = 'Hi,\n\n' +
224 blockedString +
225 '\n\n' +
226 'Cheers,\n' +
227 `PeerTube.`
228
229 const to = user.email
230 const emailPayload: EmailPayload = {
231 to: [ to ],
232 subject: '[PeerTube] Account ' + blockedWord,
233 text
234 }
235
236 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
237 }
238
ecb4e35f 239 sendMail (to: string[], subject: string, text: string) {
cef534ed 240 if (!this.enabled) {
ecb4e35f
C
241 throw new Error('Cannot send mail because SMTP is not configured.')
242 }
243
244 return this.transporter.sendMail({
245 from: CONFIG.SMTP.FROM_ADDRESS,
246 to: to.join(','),
247 subject,
248 text
249 })
250 }
251
252 private dieOnConnectionFailure (err?: Error) {
d5b7d911 253 logger.error('Failed to connect to SMTP %s:%d.', CONFIG.SMTP.HOSTNAME, CONFIG.SMTP.PORT, { err })
ecb4e35f
C
254 process.exit(-1)
255 }
256
257 static get Instance () {
258 return this.instance || (this.instance = new this())
259 }
260}
261
262// ---------------------------------------------------------------------------
263
264export {
265 Emailer
266}