{"record":{"id":"03027699c184d076","repo":"RocketChat/Rocket.Chat","slug":"error-action-not-allowed-030276","errorCode":"error-action-not-allowed","errorMessage":"Mailing is not allowed","messagePattern":"Mailing is not allowed","errorType":"exception","errorClass":"Meteor.Error","httpStatus":400,"severity":"error","filePath":"apps/meteor/server/api/v1/rooms.ts","lineNumber":1016,"sourceCode":"\t\tresponse: {\n\t\t\t200: ajv.compile<void | { missing: string[] }>({\n\t\t\t\ttype: 'object',\n\t\t\t\tproperties: {\n\t\t\t\t\tsuccess: { type: 'boolean', enum: [true] },\n\t\t\t\t\tmissing: { type: 'array', items: { type: 'string' } },\n\t\t\t\t},\n\t\t\t\trequired: ['success'],\n\t\t\t\tadditionalProperties: false,\n\t\t\t}),\n\t\t\t400: validateBadRequestErrorResponse,\n\t\t\t401: validateUnauthorizedErrorResponse,\n\t\t},\n\t},\n\tasync function action() {\n\t\tconst { rid, type } = this.bodyParams;\n\n\t\tif (!(await hasPermissionAsync(this.user, 'mail-messages', rid))) {\n\t\t\tthrow new Meteor.Error('error-action-not-allowed', 'Mailing is not allowed');\n\t\t}\n\n\t\tconst room = await Rooms.findOneById(rid);\n\t\tif (!room) {\n\t\t\tthrow new Meteor.Error('error-invalid-room');\n\t\t}\n\n\t\tconst user = await Users.findOneById(this.userId);\n\n\t\tif (!user || !(await canAccessRoomAsync(room, user))) {\n\t\t\tthrow new Meteor.Error('error-not-allowed', 'Not Allowed');\n\t\t}\n\n\t\tif (type === 'file') {\n\t\t\tconst { dateFrom, dateTo } = this.bodyParams;\n\t\t\tconst { format } = this.bodyParams;\n\n\t\t\tconst convertedDateFrom = dateFrom ? new Date(dateFrom) : new Date(0);","sourceCodeStart":998,"sourceCodeEnd":1034,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/e4b8178b205510181a96ceefee043d0abcd13e5a/apps/meteor/server/api/v1/rooms.ts#L998-L1034","documentation":"Thrown by POST /api/v1/rooms.export when the authenticated caller lacks the 'mail-messages' permission for the target room (hasPermissionAsync(this.user, 'mail-messages', rid) is false). It is the first check in the action, running before the room or user lookups, and guards both export modes (file and email).","triggerScenarios":"POST rooms.export as a regular user or a bot whose role has no 'mail-messages' permission; a room-scoped grant of mail-messages for a different rid; permission revoked after the integration was built.","commonSituations":"Custom export tools run with bot tokens that were never granted mail-messages; admins tightening permissions during audits breaking existing export jobs; role permission changes not propagated to room scope.","solutions":["Grant 'mail-messages' to the caller's role (Administration > Permissions), globally or scoped to the room","Run the export as a user who already holds the permission (typically an admin)","Catch this error and surface a permission request instead of retrying"],"exampleFix":"// before\nawait sdk.post('rooms.export', { rid, type: 'email', toUsers: ['me'], subject: 'log', messages: [] }); // as plain bot\n\n// after\n// admin grants mail-messages to the bot role, then:\nawait sdk.post('rooms.export', { rid, type: 'email', toUsers: ['me'], subject: 'log', messages: [] });","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await sdk.post('rooms.export', { rid, type, ...payload });\n} catch (e: any) {\n  if (e?.response?.data?.errorType === 'error-action-not-allowed') {\n    throw new Error('caller lacks mail-messages permission for this room — grant it and retry');\n  }\n  throw e;\n}","preventionTips":["Grant mail-messages to service accounts at provisioning time, not on failure","Run export jobs with tokens whose permissions you control","Audit role permissions after workspace permission sweeps"],"tags":["rooms","export","permissions","rest-api"],"backgroundTag":"permission-denied","analyzedSha":"e4b8178b205510181a96ceefee043d0abcd13e5a","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}