Is there a way to intervene and get the token and send the link through my own email function?
I’d like to send the forgot password e-mails through mailguns API so I can use their templates.
Is there a way to intervene and get the token and send the link through my own email function?
I’d like to send the forgot password e-mails through mailguns API so I can use their templates.
You could set your MAIL_URL
setting to mailgun, so all your email goes via them
Hmm , But I don’t think there is a way I can utilize their templates then. I currently send e-mails through the API as such, So I was hoping to have a way to specify the link in the JSON data.
'mail.newContact.notification'(contact){
let sendTo = Meteor.settings.NOTIFY_EMAIL
let subject = `New Contact for ${Meteor.settings.SITE_NAME}: ${contact.name}`
const mg = mailgun({apiKey: Meteor.settings.MAILGUN_API, domain: Meteor.settings.MAILGUN_DOMAIN});
let data = {
from: Meteor.settings.SERVER_EMAIL,
to: sendTo,
subject: subject,
template: "newcontact-notification",
'h:X-Mailgun-Variables': `${JSON.stringify(contact)}`
};
mg.messages().send(data, function (error, body) {
console.log(body);
});
},
In that case, you could replace the email
package with your own implementation which uses the API instead.
Copy the email folder from the meteor repo into your project under /packages/email/
and then edit the code to use the API when Email.send
is used
That’s what I did, except I didnt copy the email package first, I just wrote my own Email.send()
function which replaced the default function, and which uses the mailgun api.
I’ve done this - a slightly different way to the above but perhaps overriding the Email.send might be a better approach? Not sure so I’ll post my solution in the hopes of a discussion.
My ‘Reset Password’ button, rather than using the Accounts Password built in helper function, calls my own method:
// Allow reset password email to be sent via Postmark
export const resetPassword = new ValidatedMethod({
name: 'reset-password',
validate: new SimpleSchema({
email: String,
}).validator(),
run({ email }) {
if ( !Meteor.isSimulation && Meteor.isServer ) {
// This is a function that links to Postmark and sends out the reset password email
const {
sendResetPwEmail,
} = require('../../helpers/server/emailNotifications');
const user = Accounts.findUserByEmail(email);
if (!user) {
// TODO: Send an email here rather than throwing an error
throw new Meteor.Error(
'no-such-user',
`No user exists with this username`,
);
}
// Create a password reset token
// Reference 1: https://github.com/meteor/meteor/blob/49c9d07be833561a789f57581416638bca4d249d/packages/accounts-password/password_server.js#L541-L554
// Reference 2: https://github.com/poetic/accounts-passwordless/blob/master/server/send-login-email.js
const tokenRecord = {
token: Random.secret(),
email,
when: new Date(),
};
Meteor.users.update(
{ _id: user._id },
{ $set: { 'services.password.reset': tokenRecord } },
);
Meteor._ensure(user, 'services', 'password').reset = tokenRecord;
// Send the email
const resetUrl = Meteor.absoluteUrl(
`reset-password/${tokenRecord.token}`,
);
sendResetPwEmail({
to: user.emails[0].address,
vars: {
resetUrl,
// other data from the user object to personalise this
},
});
}
},
});
As per the comments, I relied heavily on these two references to write this function:
In addition to overwriting the default Email.send()
function, I should add that I also replace the Accounts.emailTemplates...
functions with functions which return a mailgun template object instead of text.
I use one ‘generic’ template and change the title, message and button by using template variables. E.g.:
Accounts.emailTemplates.resetPassword.text = function (user, url) {
return {
title: "Forgot your password?",
html: "It happens to the best of us. The good news is you can change it right now.",
link: url,
button: "RESET YOUR PASSWORD",
};
};
Then, replace Email.send
with…
const mailgun = require('mailgun-js')({
apiKey: Meteor.settings.private.mailgun.apiKey,
domain: Meteor.settings.private.mailgun.domain,
});
// overwrite default Email.send function which is used internally by the Accounts packages...
Email.send = function(options) {
...
// use mailgun templates?
if (typeof options.text=='object') {
options.template = 'generic';
options['h:X-Mailgun-Variables'] = JSON.stringify(options.text);
delete options.text;
}
...
mailgun.messages().send(options).then(...).catch(...);
...
}