mail.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. const logger = require('@alias/logger')('growi:service:mail');
  2. const nodemailer = require('nodemailer');
  3. const swig = require('swig-templates');
  4. const S2sMessage = require('../models/vo/s2s-message');
  5. const S2sMessageHandlable = require('./s2s-messaging/handlable');
  6. class MailService extends S2sMessageHandlable {
  7. constructor(crowi) {
  8. super();
  9. this.appService = crowi.appService;
  10. this.configManager = crowi.configManager;
  11. this.s2sMessagingService = crowi.s2sMessagingService;
  12. this.mailConfig = {};
  13. this.mailer = {};
  14. /**
  15. * the flag whether mailer is set up successfully
  16. */
  17. this.isMailerSetup = false;
  18. this.initialize();
  19. }
  20. /**
  21. * @inheritdoc
  22. */
  23. shouldHandleS2sMessage(s2sMessage) {
  24. const { eventName, updatedAt } = s2sMessage;
  25. if (eventName !== 'mailServiceUpdated' || updatedAt == null) {
  26. return false;
  27. }
  28. return this.lastLoadedAt == null || this.lastLoadedAt < new Date(s2sMessage.updatedAt);
  29. }
  30. /**
  31. * @inheritdoc
  32. */
  33. async handleS2sMessage(s2sMessage) {
  34. const { configManager } = this;
  35. logger.info('Initialize mail settings by pubsub notification');
  36. await configManager.loadConfigs();
  37. this.initialize();
  38. }
  39. async publishUpdatedMessage() {
  40. const { s2sMessagingService } = this;
  41. if (s2sMessagingService != null) {
  42. const s2sMessage = new S2sMessage('mailServiceUpdated', { updatedAt: new Date() });
  43. try {
  44. await s2sMessagingService.publish(s2sMessage);
  45. }
  46. catch (e) {
  47. logger.error('Failed to publish update message with S2sMessagingService: ', e.message);
  48. }
  49. }
  50. }
  51. initialize() {
  52. const { appService, configManager } = this;
  53. this.isMailerSetup = false;
  54. if (!configManager.getConfig('crowi', 'mail:from')) {
  55. this.mailer = null;
  56. return;
  57. }
  58. const transmissionMethod = configManager.getConfig('crowi', 'mail:transmissionMethod');
  59. if (transmissionMethod === 'smtp') {
  60. this.mailer = this.createSMTPClient();
  61. }
  62. else if (transmissionMethod === 'ses') {
  63. this.mailer = this.createSESClient();
  64. }
  65. else {
  66. this.mailer = null;
  67. }
  68. if (this.mailer != null) {
  69. this.isMailerSetup = true;
  70. }
  71. this.mailConfig.from = configManager.getConfig('crowi', 'mail:from');
  72. this.mailConfig.subject = `${appService.getAppTitle()}からのメール`;
  73. logger.debug('mailer initialized');
  74. }
  75. createSMTPClient(option) {
  76. const { configManager } = this;
  77. logger.debug('createSMTPClient option', option);
  78. if (!option) {
  79. const host = configManager.getConfig('crowi', 'mail:smtpHost');
  80. const port = configManager.getConfig('crowi', 'mail:smtpPort');
  81. if (host == null || port == null) {
  82. return null;
  83. }
  84. option = { // eslint-disable-line no-param-reassign
  85. host,
  86. port,
  87. };
  88. if (configManager.getConfig('crowi', 'mail:smtpUser') && configManager.getConfig('crowi', 'mail:smtpPassword')) {
  89. option.auth = {
  90. user: configManager.getConfig('crowi', 'mail:smtpUser'),
  91. pass: configManager.getConfig('crowi', 'mail:smtpPassword'),
  92. };
  93. }
  94. if (option.port === 465) {
  95. option.secure = true;
  96. }
  97. }
  98. option.tls = { rejectUnauthorized: false };
  99. const client = nodemailer.createTransport(option);
  100. logger.debug('mailer set up for SMTP', client);
  101. return client;
  102. }
  103. createSESClient(option) {
  104. const { configManager } = this;
  105. if (!option) {
  106. const accessKeyId = configManager.getConfig('crowi', 'mail:sesAccessKeyId');
  107. const secretAccessKey = configManager.getConfig('crowi', 'mail:sesSecretAccessKey');
  108. if (accessKeyId == null || secretAccessKey == null) {
  109. return null;
  110. }
  111. option = { // eslint-disable-line no-param-reassign
  112. accessKeyId,
  113. secretAccessKey,
  114. };
  115. }
  116. const ses = require('nodemailer-ses-transport');
  117. const client = nodemailer.createTransport(ses(option));
  118. logger.debug('mailer set up for SES', client);
  119. return client;
  120. }
  121. setupMailConfig(overrideConfig) {
  122. const c = overrideConfig;
  123. let mc = {};
  124. mc = this.mailConfig;
  125. mc.to = c.to;
  126. mc.from = c.from || this.mailConfig.from;
  127. mc.text = c.text;
  128. mc.subject = c.subject || this.mailConfig.subject;
  129. return mc;
  130. }
  131. async send(config) {
  132. if (this.mailer == null) {
  133. throw new Error('Mailer is not completed to set up. Please set up SMTP or AWS setting.');
  134. }
  135. const templateVars = config.vars || {};
  136. const output = await swig.renderFile(
  137. config.template,
  138. templateVars,
  139. );
  140. config.text = output;
  141. return this.mailer.sendMail(this.setupMailConfig(config));
  142. }
  143. }
  144. module.exports = MailService;