RocketChat/Rocket.Chat · error · Meteor.Error
error-action-not-allowed
error-action-not-allowed
Error message
Mailing is not allowed
What it means
Thrown by POST rooms.mail when the calling user lacks the 'mail-messages' permission for the given room (rid). The mail/export route is gated behind a permission usually reserved for admins/moderators; without it the request never proceeds.
Source
Thrown at apps/meteor/server/api/v1/rooms.ts:1012
response: {
200: ajv.compile<void | { missing: string[] }>({
type: 'object',
properties: {
success: { type: 'boolean', enum: [true] },
missing: { type: 'array', items: { type: 'string' } },
},
required: ['success'],
additionalProperties: false,
}),
400: validateBadRequestErrorResponse,
401: validateUnauthorizedErrorResponse,
},
},
async function action() {
const { rid, type } = this.bodyParams;
if (!(await hasPermissionAsync(this.user, 'mail-messages', rid))) {
throw new Meteor.Error('error-action-not-allowed', 'Mailing is not allowed');
}
const room = await Rooms.findOneById(rid);
if (!room) {
throw new Meteor.Error('error-invalid-room');
}
const user = await Users.findOneById(this.userId);
if (!user || !(await canAccessRoomAsync(room, user))) {
throw new Meteor.Error('error-not-allowed', 'Not Allowed');
}
if (type === 'file') {
const { dateFrom, dateTo } = this.bodyParams;
const { format } = this.bodyParams;
const convertedDateFrom = dateFrom ? new Date(dateFrom) : new Date(0);View on GitHub (pinned to f9d3ec372b)
Solutions
- Grant 'mail-messages' to the user's role in Permissions admin (or via permissions API).
- If the feature shouldn't be exposed, hide the UI control for users without the permission.
- For scoped setups, ensure the permission is granted for the specific rid/channel, not just globally.
Example fix
// before
await rest.post('/api/v1/rooms.mail', { rid, type: 'email' });
// after
const me = await rest.get('/api/v1/me');
if (!me.permissions?.includes('mail-messages')) {
notifyUser('Mailing requires the mail-messages permission.');
} else {
await rest.post('/api/v1/rooms.mail', { rid, type: 'email' });
} Defensive patterns
Strategy: validation
Validate before calling
const me = await rest.get('/api/v1/me');
const canMail = (me.roles ?? []).some(r => ['admin'].includes(r))
|| (me.permissions ?? []).includes('mail-messages');
if (!canMail) throw new Error('mail-messages permission required'); Type guard
function hasMailPermission(perms: string[] | undefined): boolean {
return Array.isArray(perms) && perms.includes('mail-messages');
} Try / catch
try {
await rest.post('/api/v1/rooms.mail', { rid, type });
} catch (e) {
if (isMeteorError(e, 'error-action-not-allowed')) {
notify('You need the mail-messages permission.');
} else throw e;
} Prevention
- Hide the mail/export action for users without 'mail-messages'.
- Grant the permission to the relevant role in admin.
- Check scoped room-level permission for private channels.
When it happens
Trigger: POST /api/v1/rooms.mail with { rid, type } where hasPermissionAsync(user, 'mail-messages', rid) is false.
Common situations: Regular (non-admin) users trying the mail/export feature; permission renamed or removed in a policy reset; custom role that forgot to include 'mail-messages'; scoped permissions not granted for the target room.
Related errors
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/03027699c184d076.
Report an issue: GitHub.