Accounts.sendLoginEmail = function (userId, address) { // XXX Also generate a link using which someone can delete this // account if they own said address but weren't those who created // this account. // Make sure the user exists, and address is one of their addresses. var user = Meteor.users.findOne(userId); if (!user) throw new Error("Can't find user"); // pick the first unverified address if we weren't passed an address. if (!address) { var email = _.find(user.emails || [], function (e) { return !e.verified; }); address = (email || {}).address; } // make sure we have a valid address if (!address || !_.contains(_.pluck(user.emails || [], 'address'), address)) throw new Error("No such email address for user."); var tokenRecord = { token: Random.secret(), address: address, when: new Date()}; Meteor.users.update( {_id: userId}, {$push: {'services.email.verificationTokens': tokenRecord}}); // before passing to template, update user object with new token Meteor._ensure(user, 'services', 'email'); if (!user.services.email.verificationTokens) { user.services.email.verificationTokens = []; } user.services.email.verificationTokens.push(tokenRecord); var loginUrl = Accounts.urls.verifyEmail(tokenRecord.token); var options = { to: email, from: Accounts.emailTemplates.loginNoPassword.from ? Accounts.emailTemplates.loginNoPassword.from(user) : Accounts.emailTemplates.from, subject: Accounts.emailTemplates.loginNoPassword.subject(user) }; if (typeof Accounts.emailTemplates.loginNoPassword.text === 'function') { options.text = Accounts.emailTemplates.loginNoPassword.text(user, loginUrl); } if (typeof Accounts.emailTemplates.loginNoPassword.html === 'function') options.html = Accounts.emailTemplates.loginNoPassword.html(user, loginUrl); if (typeof Accounts.emailTemplates.headers === 'object') { options.headers = Accounts.emailTemplates.headers; } Email.send(options); };
export async function sendResetPasswordEmail(userId, optionalEmail) { // Make sure the user exists, and email is one of their addresses. const user = Meteor.users.findOne(userId); if (!user) { Logger.error("sendResetPasswordEmail - User not found"); throw new Meteor.Error("not-found", "User not found"); } let email = optionalEmail; // pick the first email if we weren't passed an email. if (!optionalEmail && user.emails && user.emails[0]) { email = user.emails[0].address; } // make sure we have a valid email if (!email || !user.emails || !user.emails.map((mailInfo) => mailInfo.address).includes(email)) { Logger.error("sendResetPasswordEmail - Email not found"); throw new Meteor.Error("not-found", "Email not found"); } // Create token for password reset const token = Random.secret(); const when = new Date(); const tokenObj = { token, email, when }; Meteor.users.update(userId, { $set: { "services.password.reset": tokenObj } }); Meteor._ensure(user, "services", "password").reset = tokenObj; // Get shop data for email display const shop = Shops.findOne(Reaction.getShopId()); const emailLogo = Reaction.Email.getShopLogo(shop); const copyrightDate = new Date().getFullYear(); const dataForEmail = { // Shop Data shop, contactEmail: shop.emails[0].address, homepage: Meteor.absoluteUrl(), emailLogo, copyrightDate, legalName: _.get(shop, "addressBook[0].company"), physicalAddress: { address: `${_.get(shop, "addressBook[0].address1")} ${_.get(shop, "addressBook[0].address2")}`, city: _.get(shop, "addressBook[0].city"), region: _.get(shop, "addressBook[0].region"), postal: _.get(shop, "addressBook[0].postal") }, shopName: shop.name, socialLinks: { display: true, facebook: { display: true, icon: `${Meteor.absoluteUrl()}resources/email-templates/facebook-icon.png`, link: "https://www.facebook.com" }, googlePlus: { display: true, icon: `${Meteor.absoluteUrl()}resources/email-templates/google-plus-icon.png`, link: "https://plus.google.com" }, twitter: { display: true, icon: `${Meteor.absoluteUrl()}resources/email-templates/twitter-icon.png`, link: "https://www.twitter.com" } }, // Account Data passwordResetUrl: Accounts.urls.resetPassword(token), user }; // Compile Email with SSR const tpl = "accounts/resetPassword"; const subject = "accounts/resetPassword/subject"; SSR.compileTemplate(tpl, Reaction.Email.getTemplate(tpl)); SSR.compileTemplate(subject, Reaction.Email.getSubject(tpl)); return Reaction.Email.send({ to: email, from: Reaction.getShopEmail(), subject: SSR.render(subject, dataForEmail), html: SSR.render(tpl, dataForEmail) }); }
export function sendResetPasswordEmail(userId, optionalEmail) { // Make sure the user exists, and email is one of their addresses. const user = Meteor.users.findOne(userId); if (!user) { Logger.error("sendResetPasswordEmail - User not found"); throw new Meteor.Error("user-not-found", "User not found"); } let email = optionalEmail; // pick the first email if we weren't passed an email. if (!optionalEmail && user.emails && user.emails[0]) { email = user.emails[0].address; } // make sure we have a valid email if (!email || !user.emails || !user.emails.map((mailInfo) => mailInfo.address).includes(email)) { Logger.error("sendResetPasswordEmail - Email not found"); throw new Meteor.Error("email-not-found", "Email not found"); } // Create token for password reset const token = Random.secret(); const when = new Date(); const tokenObj = { token, email, when }; Meteor.users.update(userId, { $set: { "services.password.reset": tokenObj } }); Meteor._ensure(user, "services", "password").reset = tokenObj; // Get shop data for email display const shop = Shops.findOne(Reaction.getShopId()); // Get shop logo, if available. If not, use default logo from file-system let emailLogo; if (Array.isArray(shop.brandAssets)) { const brandAsset = _.find(shop.brandAssets, (asset) => asset.type === "navbarBrandImage"); const mediaId = Media.findOne(brandAsset.mediaId); emailLogo = path.join(Meteor.absoluteUrl(), mediaId.url()); } else { emailLogo = Meteor.absoluteUrl() + "resources/email-templates/shop-logo.png"; } const dataForEmail = { // Shop Data shop: shop, contactEmail: shop.emails[0].address, homepage: Meteor.absoluteUrl(), emailLogo: emailLogo, copyrightDate: moment().format("YYYY"), legalName: shop.addressBook[0].company, physicalAddress: { address: shop.addressBook[0].address1 + " " + shop.addressBook[0].address2, city: shop.addressBook[0].city, region: shop.addressBook[0].region, postal: shop.addressBook[0].postal }, shopName: shop.name, socialLinks: { display: true, facebook: { display: true, icon: Meteor.absoluteUrl() + "resources/email-templates/facebook-icon.png", link: "https://www.facebook.com" }, googlePlus: { display: true, icon: Meteor.absoluteUrl() + "resources/email-templates/google-plus-icon.png", link: "https://plus.google.com" }, twitter: { display: true, icon: Meteor.absoluteUrl() + "resources/email-templates/twitter-icon.png", link: "https://www.twitter.com" } }, // Account Data passwordResetUrl: Accounts.urls.resetPassword(token), user: user }; // Compile Email with SSR const tpl = "accounts/resetPassword"; const subject = "accounts/resetPassword/subject"; SSR.compileTemplate(tpl, Reaction.Email.getTemplate(tpl)); SSR.compileTemplate(subject, Reaction.Email.getSubject(tpl)); return Reaction.Email.send({ to: email, from: Reaction.getShopEmail(), subject: SSR.render(subject, dataForEmail), html: SSR.render(tpl, dataForEmail) }); }
if (!user) return new Meteor.Error('email-doesnt-exist'); const userId = user._id; const token = Random.secret(); const when = new Date(); const tokenRecord = { token, email, when, }; Meteor.users.update(userId, { $set: { 'services.password.reset': tokenRecord, }, }); // before passing to template, update user object with new token Meteor._ensure(user, 'services', 'password').reset = tokenRecord; const client = new PostmarkClient(Meteor.settings.postmark.serverKey); const sendEmailWithTemplate = Meteor.wrapAsync(client.sendEmailWithTemplate, client); const res = sendEmailWithTemplate({ From: '*****@*****.**', TemplateId: 1287034, To: email, TemplateModel: { name: user.profile.name, action_url: `https://dashboard.worona.org/recover-password?token=${tokenRecord.token}`, }, }); return res;