Closed DennisSnijder closed 2 years ago
Currently I'm using a workaround to make this work:
I register the MailerModule with .forRootAsync
and inject the I18nModule. From there I copied the handlebars helpers implementation from the nestjs-i18n library and implemented them myself using the injected I18nService 😄
@DennisSnijder any idea in how we could better incorporate this in the library? So that NestJS mailer
works more out of the box?
@DennisSnijder any idea in how we could better incorporate this in the library? So that NestJS
mailer
works more out of the box?
@toonvanstrijp I don't think there is an easy solution to this yet...
A hypothetical solution could be to conditionally include the mailer module when it's enabled and/or exists as a dependency and inject a new helper function into the ViewAdapter
? Problem is: those ViewAdapters
are not publicly exposed from the MailerService
😢.
Perhaps a first step towards an easy out of the box solution is to open a pull request on the mailer module so the ViewAdapter is getting exposed? 🤔
@DennisSnijder I took a look at the source code of nestjs mailer. And from what I can tell the HandlebarsAdapter
allows you to pass down helpers
via the constructor. What if you make use of the forRootAsync
and then we create a helper function on the I18nService
that can be passed down directly? This way you don't have to copy any code and it's a bit easier to implement.
@toonvanstrijp That does help a lot! That's somewhat like the approach I'm using at the moment 😄.
Not the easy plug and play version like you got going on with the viewEngine: 'hbs'
, but that would be a great addition!
My current module setup:
@Module({
imports: [
I18nModule.forRoot(...I18nOptions),
MailerModule.forRootAsync({
inject: [ I18nService ],
useFactory: (i18nService: I18nService) => ({
transport: {
host: process.env.EMAIL_HOST,
port: process.env.EMAIL_PORT,
auth: {
user: process.env.EMAIL_ID,
pass: process.env.EMAIL_PASS
}
},
template: {
dir: path.join(__dirname, '../resources/templates/'),
adapter: new HandlebarsAdapter(getHandlebarsHelpers(i18nService))
},
})
}),
]
})
and the Handlebars helpers being: (pretty much copied this from this repo)
export const getHandlebarsHelpers = (i18nService: I18nService) => {
return {
t: (key: string, args: any, options: any) => {
if (!options) {
options = args;
}
const lang = options.lookupProperty(options.data.root, 'i18nLang');
return i18nService.translate(key, {lang, args});
}
};
}
If there would be something like getHandlebarHelpers
on the I18nService, that would be awesome 😄
@DennisSnijder thanks! It's released in V9.0.8. I also added a doc page: https://nestjs-i18n.com/guides/mailer. @DennisSnijder thanks for the help!
@toonvanstrijp Woah, that was fast! Thanks! 🥳
Good solve but async problem to me
[object Promise]
Hi,
In my tests sending an email with MailerService.sendMail()
and using Handlebars, getHandlebarsHelpers
isn't finding the lang from the i18nLang
property, here:
const lang = options.lookupProperty(options.data.root, 'i18nLang');
I found out I have to pass i18nLang
manually in the context of the call to sendMail
, like this:
@Controller('contact')
export class ContactController {
constructor(
private readonly mailerService: MailerService,
) {}
@Post('')
async sendEnquiry(
@Body() data: EnquiryDto,
@I18n() i18n: I18nContext
): Promise<Result<any>> {
this.mailerService
.sendMail({
to: enquiry.contactData?.email,
from: 'me@example.com',
subject: `My subject`,
template: 'enquiry',
context: {
i18nLang: i18n.lang || 'es-ES',
enquiry,
},
})
.then((res) => {
resolve(res);
})
.catch((err) => {
console.error(err);
reject(err);
});
}
}
I think this isn't documented anywhere.
The NestJS Mailer module has support for using Handlebars/Pugs/EJS. However... this is a different View-engine instance than what is being used to return a view from a controller. This results in the helper functions being unavailable when rendering an email.
NestJS mailer docs: https://nest-modules.github.io/mailer/docs/mailer