【问题标题】:Send email with Loopback 4使用 Loopback 4 发送电子邮件
【发布时间】:2019-12-02 13:36:26
【问题描述】:

我对 Loopback 和 Typescript 有点陌生,所以我不知道如何实现它。我正在尝试直接调用 Nodemailer,但到目前为止我一直收到错误消息。

我的邮件服务:

import { SentMessageInfo } from 'nodemailer';
import Mail = require('nodemailer/lib/mailer');
const nodemailer = require("nodemailer");

export class MailerService {
  async sendMail(mailOptions: Mail.Options): Promise<SentMessageInfo> {
    const transporter = nodemailer.createTransport({
      host: 'smtp.ethereal.email',
      port: 587,
      auth: {
        user: 'albert.grimes@ethereal.email',
        pass: 'qN85JT6SneBA9S5dhy'
      }
    });
    return await transporter.sendMail(mailOptions);
  }
}

我的邮件控制器:

import { Request, RestBindings, get, ResponseObject } from 

'@loopback/rest';
import { inject } from '@loopback/context';
import { MailerService } from "../services";

export class MailController {
  constructor(
    @inject ???
    public mailerService: MailerService
  ) { }

  @get('/mail/acceptation')
  async sendEmail(email: string): Promise<any> {
    let info = await this.mailerService.sendMail({
      to: `${email}`,
      subject: 'testmail',
      html: '<p>Hallo</p>'
    })
    return info;
  }
}

我一直认为这是一个错误:

GET /mail/acceptation 中未处理的错误:500 错误:无法解析 MailController.prototype.sendEmail[0] 的注入参数:参数[0] 未针对依赖注入进行修饰,但未提供值

所以我从中收集到的是我应该在我的控制器中注入一个值,但我不知道是什么。

【问题讨论】:

    标签: javascript typescript strongloop loopback loopback4


    【解决方案1】:

    email.service.ts

    import Utils from '../utils';
    import * as nodemailer from 'nodemailer';
    import { IEmail } from '../type-schema';
    
    export interface EmailManager<T = Object> {
      sendMail(mailObj: IEmail): Promise<T>;
    }
    
    export class EmailService {
      constructor() { }
    
      async sendMail(mailObj: IEmail): Promise<object> {
        const configOption = Utils.getSiteOptions();
    
        let transporter = nodemailer.createTransport(configOption.email);
    
        return await transporter.sendMail(mailObj);
      }
    }
    

    在您的配置文件中定义您的 smtp 选项,如下所示:-

    "email": {
        "type": "smtp",
        "host": "smtp.gmail.com",
        "secure": true,
        "port": 465,
        "tls": {
          "rejectUnauthorized": false
        },
        "auth": {
          "user": "example@gmail.com",
          "pass": "sample-password"
        }
      }
    

    在控制器中发送邮件,如下方式:-

    import { EmailManager } from '../services/email.service';
    import { EmailManagerBindings } from '../keys';
    
    // inject in constructor
    @inject(EmailManagerBindings.SEND_MAIL) public emailManager: EmailManager,
    
    // call service method like following way
    const mailOptions = {
              from: configOption.fromMail,
              to: getUser.email,
              subject: template.subject,
              html: Utils.filterEmailContent(template.message, msgOpt)
            };
    
            await this.emailManager.sendMail(mailOptions).then(function (res: any) {
              return { message: `Successfully sent reset mail to ${getUser.email}` };
            }).catch(function (err: any) {
              throw new HttpErrors.UnprocessableEntity(`Error in sending E-mail to ${getUser.email}`);
            });
    

    简单方法:- 如果您不想创建服务功能,只需在控制器中导入 nodemailer 并发送邮件,但这不是一个好方法。

    import * as nodemailer from 'nodemailer';
    
    let transporter = nodemailer.createTransport({
        "type": "smtp",
        "host": "smtp.gmail.com",
        "secure": true,
        "port": 465,
        "tls": {
          "rejectUnauthorized": false
        },
        "auth": {
          "user": "example@gmail.com",
          "pass": "sample-password"
        }
      });
    
     return await transporter.sendMail({
              from: "sender-email",
              to: "receiver-email",
              subject: "email-subject",
              html: "message body"
            });
    

    更新:-

    keys.ts

    import { BindingKey } from '@loopback/context';    
    import { EmailManager } from './services/email.service';    
    import { Member } from './models';
    import { Credentials } from './type-schema';
    
    export namespace PasswordHasherBindings {
      export const PASSWORD_HASHER = BindingKey.create<PasswordHasher>('services.hasher');
      export const ROUNDS = BindingKey.create<number>('services.hasher.round');
    }
    
    export namespace UserServiceBindings {
      export const USER_SERVICE = BindingKey.create<UserService<Member, Credentials>>('services.user.service');
    }
    
    export namespace TokenManagerBindings {
      export const TOKEN_HANDLER = BindingKey.create<TokenManager>('services.token.handler');
    }
    
    export namespace EmailManagerBindings {
      export const SEND_MAIL = BindingKey.create<EmailManager>('services.email.send');
    }
    

    aplication.ts

    import { BootMixin } from '@loopback/boot';
    import { ApplicationConfig } from '@loopback/core';
    import { RepositoryMixin } from '@loopback/repository';
    import { RestApplication } from '@loopback/rest';
    import { ServiceMixin } from '@loopback/service-proxy';
    import * as path from 'path';
    import { MySequence } from './sequence';
    
    import { TokenServiceBindings, UserServiceBindings, TokenServiceConstants, } from './keys';
    import { JWTService, TokenGenerator } from './services/jwt-service';
    import { EmailService } from './services/email.service';
    import { MyUserService } from './services/user-service';
    import { AuthenticationComponent, registerAuthenticationStrategy, } from '@loopback/authentication';
    import { PasswordHasherBindings, TokenManagerBindings, EmailManagerBindings } from './keys';
    import { BcryptHasher } from './services/hash.password.bcryptjs';
    import { JWTAuthenticationStrategy } from './authentication-strategies/jwt-strategy';
    
    export class AmpleServerApplication extends BootMixin(ServiceMixin(RepositoryMixin(RestApplication))) {
      constructor(options: ApplicationConfig = {}) {
        super(options);
    
        this.setUpBindings();
    
        // Bind authentication component related elements
        this.component(AuthenticationComponent);
    
        registerAuthenticationStrategy(this, JWTAuthenticationStrategy);
    
        // Set up the custom sequence
        this.sequence(MySequence);
    
        // Set up default home page
        this.static('/', path.join(__dirname, '../public'));
    
        this.projectRoot = __dirname;
    
        this.bootOptions = {
          controllers: {
            dirs: ['controllers'],
            extensions: ['.controller.js'],
            nested: true,
          },
        };
      }
    
      setUpBindings(): void {
        this.bind(TokenServiceBindings.TOKEN_SECRET).to(TokenServiceConstants.TOKEN_SECRET_VALUE);
        this.bind(TokenServiceBindings.TOKEN_EXPIRES_IN).to(TokenServiceConstants.TOKEN_EXPIRES_IN_VALUE);
    
        this.bind(UserServiceBindings.USER_SERVICE).toClass(MyUserService);
    
        this.bind(EmailManagerBindings.SEND_MAIL).toClass(EmailService);
      }
    }
    

    【讨论】:

    • 回复晚了,抱歉。你能告诉我如何将你的服务绑定到应用程序吗?这是我遇到的最后一件事。
    • @Peterrosevelt 我已更新我的答案以显示“如何在我的用户控制器文件中绑定电子邮件服务?”
    【解决方案2】:

    https://loopback.io/doc/en/lb3/Email-connector.html 上有一个教程。它有一个特殊的邮件连接器,可以用作数据源。模型应该能够处理发送细节。该过程应该与使用 lb4 cli 创建数据库连接器时几乎相同。

    cli

    lb4 datasource //select email
    

    datasources.json

    {
      ...
      "myEmailDataSource": {
        "connector": "mail",
        "transports": [{
          "type": "smtp",
          "host": "smtp.private.com",
          "secure": false,
          "port": 587,
          "tls": {
            "rejectUnauthorized": false
          },
          "auth": {
            "user": "me@private.com",
            "pass": "password"
          }
        }]
      }
      ...
    }
    

    型号

    module.exports = function(MyModel) {
      // send an email
      MyModel.sendEmail = function(cb) {
        MyModel.app.models.Email.send({
          to: 'foo@bar.com',
          from: 'you@gmail.com',
          subject: 'my subject',
          text: 'my text',
          html: 'my <em>html</em>'
        }, function(err, mail) {
          console.log('email sent!');
         cb(err);
        });
      }
    };`
    

    【讨论】:

    • Loopback 4 的任何文档?
    【解决方案3】:

    您应该有一个文件来存储您的Bindings。在那里你必须创建绑定密钥:

    export namespace MailerBindings {
      export const SERVICE = BindingKey.create<MailerService>('mailer.services');
    }
    

    要真正绑定服务,您必须在应用程序的构造函数中调用绑定函数:

    this.bind(MailerBindings.SERVICE).toClass(MailerService);
    

    现在您可以使用绑定注入服务:

    @inject(MailerBindings.SERVICE) public mailerService: MailerService,
    

    【讨论】:

    • 我现在更加困惑了。我不明白为什么发送电子邮件必须如此复杂。不过还是谢谢。
    • 由于实现为服务,这似乎很复杂。您可以按照下面链接中列出的方式使用它,但是您必须为您要发送邮件的应用程序的每个部分实现此功能。通过将其实现为服务,您可以在应用程序的多个部分以更简单的方式使用它。链接:nodemailer.com/about
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-10
    • 1970-01-01
    • 2014-12-31
    • 2016-04-17
    • 2017-12-07
    • 1970-01-01
    相关资源
    最近更新 更多