mail.js 4.4 KB

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