RocketChat / RocketChat/Rocket.Chat
fix: REST API POST /api/v1/sendInvitationEmail always returns success: false
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 46.1k
- Forks
- 13.9k
- Avg merge
- 3d 3h
- Merged PRs (30d)
- 130
Description
Description:
When invoking the REST API endpoint POST /api/v1/sendInvitationEmail, the endpoint constructs a response payload containing { "success": false } despite successfully delivering the invitation emails and incrementing the Invitation_Email_Count database metric.
This causes a direct violation of the endpoint's compiled AJV validation contract (sendInvitationEmailResponseSchema specifies success: { type: 'boolean', enum: [true] }), and misinforms API clients / SDK integrations that the invite request failed.
Steps to reproduce:
- Obtain an API authentication token for an account with the
bulk-register-userpermission. - Send a
POSTrequest to/api/v1/sendInvitationEmailwith a list of destination email addresses:
curl -X POST "http://localhost:3000/api/v1/sendInvitationEmail" \
-H "X-Auth-Token: <AUTH_TOKEN>" \
-H "X-User-Id: <USER_ID>" \
-H "Content-Type: application/json" \
-d '{
"emails": ["colleague@example.com"]
}'
- Inspect the JSON response body and the server logs.
Expected behavior:
- The server sends the invitation email via SMTP/Mailer.
- The server increments the
Invitation_Email_Countsetting. - The API responds with HTTP 200 and the following payload:
matching the{ "success": true }sendInvitationEmailResponseSchemadefinition (enum: [true]).
Actual behavior:
- The server sends the invitation email and increments
Invitation_Email_Count. - However, the response payload is constructed as:
falsely indicating that the operation failed.{ "success": false }
Deep Root Cause & Code Analysis:
1. Missing Return Statement in Service Layer
In apps/meteor/server/lib/rooms/invites/sendInvitationEmail.ts:
export const sendInvitationEmail = async (userId: string, emails: string[]) => {
check(emails, [String]);
// ... validation ...
for (const email of validEmails) {
try {
await Mailer.send({ ... });
const value = await Settings.incrementValueById('Invitation_Email_Count', 1, { returnDocument: 'after' });
if (value) {
void notifyOnSettingChanged(value);
}
continue;
} catch ({ message }: any) {
throw new Meteor.Error('error-email-send-failed', ...);
}
}
// ⚠️ Missing `return true;` -> async function implicitly returns Promise<undefined>
};
2. False-Evaluation in Route Handler
In apps/meteor/server/api/v1/invites.ts:
async function action() {
const { emails } = this.bodyParams;
try {
// ⚠️ Boolean(await sendInvitationEmail(...)) === Boolean(undefined) === false
return API.v1.success({ success: Boolean(await sendInvitationEmail(this.userId, emails)) });
} catch (e: unknown) {
return API.v1.failure({ error: e instanceof Error ? e.message : String(e) });
}
}
3. Violation of AJV Response Schema
In apps/meteor/server/api/v1/invites.ts:
const sendInvitationEmailResponseSchema = ajv.compile<{ success: boolean }>({
type: 'object',
properties: {
success: { type: 'boolean', enum: [true] },
},
required: ['success'],
additionalProperties: false,
});
The compiled schema explicitly requires enum: [true], but the runtime evaluation produces { success: false }.
Proposed Fix:
1. In apps/meteor/server/lib/rooms/invites/sendInvitationEmail.ts:
Add explicit return type and return statement:
-export const sendInvitationEmail = async (userId: string, emails: string[]) => {
+export const sendInvitationEmail = async (userId: string, emails: string[]): Promise<boolean> => {
check(emails, [String]);
// ...
for (const email of validEmails) {
// ...
}
+ return true;
};
2. In apps/meteor/tests/end-to-end/api/invites.ts:
Add automated test coverage:
describe('POST [/sendInvitationEmail]', () => {
it('should send invitation emails and return success: true', async () => {
const res = await request
.post(api('sendInvitationEmail'))
.set(credentials)
.send({
emails: ['test-invite-user@example.com'],
})
.expect(200);
expect(res.body).to.have.property('success', true);
});
});
Server Setup Information:
- Version of Rocket.Chat Server:
develop(latest 7.x / 8.x) - Deployment Method: Source / Docker / Kubernetes
- NodeJS Version:
20.x/22.x - MongoDB Version:
6.x/7.x - DB Replicaset Oplog: Enabled
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in apps/meteor/server/lib/rooms/invites/sendInvitationEmail.ts and apps/meteor/server/api/v1/invites.ts, then review the existing endpoint tests in apps/meteor/tests/end-to-end/api/invites.ts. Verify the service result is propagated and the POST /sendInvitationEmail response is success: true; add or run coverage for the successful invitation flow.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 88/100