{"record":{"id":"3d9cfc7ff16c2624","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-user-3d9cfc","errorCode":"error-invalid-user","errorMessage":"Invalid user","messagePattern":"Invalid user","errorType":"error_code","errorClass":"Meteor.Error","httpStatus":400,"severity":"error","filePath":"apps/meteor/server/lib/notifications/mail-messages/functions/sendMail.ts","lineNumber":43,"sourceCode":"}): Promise<void> {\n\tMailer.checkAddressFormatAndThrow(from, 'Mailer.sendMail');\n\n\tif (body.indexOf('[unsubscribe]') === -1) {\n\t\tthrow new Meteor.Error('error-missing-unsubscribe-link', 'You must provide the [unsubscribe] link.', {\n\t\t\tfunction: 'Mailer.sendMail',\n\t\t});\n\t}\n\n\tlet userQuery: Filter<any> = { 'mailer.unsubscribed': { $exists: 0 } };\n\tif (query) {\n\t\tuserQuery = { $and: [userQuery, EJSON.parse(query)] };\n\t}\n\n\tif (dryrun) {\n\t\tconst user = await Users.findOneByEmailAddress(from);\n\n\t\tif (!user) {\n\t\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\t\tfunction: 'Mailer.sendMail',\n\t\t\t});\n\t\t}\n\n\t\tconst email = `${user.name} <${user.emails?.[0].address}>`;\n\t\tconst html = placeholders.replace(body, {\n\t\t\tunsubscribe: Meteor.absoluteUrl(\n\t\t\t\tgeneratePath('mailer/unsubscribe/:_id/:createdAt', {\n\t\t\t\t\t_id: user._id,\n\t\t\t\t\tcreatedAt: user.createdAt?.getTime().toString() || '',\n\t\t\t\t}),\n\t\t\t),\n\t\t\tname: user.name,\n\t\t\temail,\n\t\t});\n\n\t\tSystemLogger.debug({\n\t\t\tmsg: 'Sending email',","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/lib/notifications/mail-messages/functions/sendMail.ts#L25-L61","documentation":"In dry-run mode Mailer.sendMail looks up the account whose email equals 'from' (Users.findOneByEmailAddress) to render one sample message; if no user matches it throws error-invalid-user. The dry-run therefore requires the from-address to belong to an existing local user account.","triggerScenarios":"Mailer.sendMail({ from: 'marketing@external.com', dryrun: true, ... }) where the address is not attached to any Rocket.Chat user; the matching user was deleted; a typo or case mismatch against the stored email.","commonSituations":"Testing the Mailer with an external or no-reply address; organization changed its from-address without a matching user account; admin testing after user cleanup.","solutions":["Set 'from' to the email of an existing user (typically your admin account) when using dryrun: true","Verify first with Users.findOneByEmailAddress(from)","Alternatively drop dryrun and constrain recipients with a narrow 'query' instead"],"exampleFix":"// before\nawait Mailer.sendMail({ from: 'noreply@external.com', subject, body, dryrun: true });\n\n// after\nconst admin = await Users.findOneByEmailAddress('admin@yourdomain.tld');\nif (!admin) throw new Error('pick a from address owned by a real user');\nawait Mailer.sendMail({ from: admin.emails[0].address, subject, body, dryrun: true });","handlingStrategy":"validation","validationCode":"const user = await Users.findOneByEmailAddress(from);\nif (!user) {\n  // dryrun needs a from address owned by an existing user\n  throw new Error('from address has no matching user');\n}\nawait Mailer.sendMail({ from, subject, body, dryrun: true });","typeGuard":null,"tryCatchPattern":"try {\n  await Mailer.sendMail({ from, subject, body, dryrun: true });\n} catch (err) {\n  if (err instanceof Meteor.Error && err.error === 'error-invalid-user') {\n    // switch 'from' to an address belonging to a real user and retry the dry run\n  } else throw err;\n}","preventionTips":["Use your own admin account's address as 'from' when testing with dryrun","Keep the sending address attached to a dedicated user account"],"tags":["mailer","dry-run","user-lookup","rocket-chat"],"backgroundTag":"entity-not-found","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}