Skip to content

Conversation

@ravi-aman
Copy link

@ravi-aman ravi-aman commented Nov 4, 2025

Proposed changes

Fixes Twilio MMS inbound functionality by handling HTTP 302 redirects when fetching media attachments.

Problem

When customers send MMS messages through Twilio, media URLs respond with HTTP 302 redirects to the actual media location. The previous implementation used redirect: 'error' which caused all MMS attachments to fail with:

FetchError: uri requested responds with a redirect, redirect mode is set to error

Users would see "An Attachment was received, but upload to server failed" in the UI, and the following error in logs:

{
  "level": 50,
  "msg": "Attachment upload failed",
  "err": {
    "type": "FetchError",
    "message": "uri requested responds with a redirect, redirect mode is set to error: https://api.twilio.com/..."
  }
}

Solution

  • Changed fetch(fileUrl, { redirect: 'error' }) to fetch(fileUrl, { redirect: 'follow' })
  • Added media URLs to message body for better visibility in conversations
  • Enhanced error logging with URL, status code, and content size for debugging

Technical Details

Files Modified:

  1. apps/meteor/app/livechat/imports/server/rest/sms.ts

    • Changed redirect mode from 'error' to 'follow' in getUploadFile() function
    • Added explanatory comment about Twilio redirect behavior
    • Enhanced error logging with URL, HTTP status, and content size
  2. apps/meteor/server/services/omnichannel-integrations/providers/twilio.ts

    • Enhanced parse() method to append media URLs to message body
    • Filters empty URLs and joins with newlines for clean display
    • Preserves original message text

Code Changes:

// sms.ts
- const response = await fetch(fileUrl, { redirect: 'error' });
+ // Follow redirects to support Twilio media URLs that redirect to actual media location
+ const response = await fetch(fileUrl, { redirect: 'follow' });

// twilio.ts
+ // Append media URLs to the message body for better visibility
+ if (returnData.media.length > 0) {
+   const links = returnData.media
+     .map((media) => media.url)
+     .filter((url) => !!url)
+     .join('\n');
+   returnData.body = [returnData.body, links].filter(Boolean).join('\n');
+ }

Security Considerations:

  • SSRF protection maintained via checkUrlForSsrf() check before redirect following
  • File size limits (5MB) still enforced
  • Content type validation remains active
  • fetch library prevents infinite redirect loops automatically

Backward Compatibility:

  • Fully compatible with existing SMS/MMS integrations
  • Regular SMS messages (no media) continue to work unchanged
  • No breaking changes to API or behavior

Lines changed: +13, -1 (net: +12 lines)


Issue(s)

Fixes #36491


Steps to test or reproduce

Prerequisites

  • Rocket.Chat instance with Omnichannel enabled
  • Twilio account with SMS/MMS capability
  • Valid Twilio credentials (Account SID and Auth Token)

Configuration Steps

  1. Login to Rocket.Chat as administrator
  2. Navigate to: Administration → Workspace → Settings → SMS
  3. Configure:
    • Enable SMS: true
    • SMS Service: twilio
    • Twilio Account SID: [Your Account SID]
    • Twilio Auth Token: [Your Auth Token]
    • File Upload Enabled: true
  4. Save settings
  5. In Twilio Console, configure webhook:
    • URL: https://your-rocket-chat-server.com/api/v1/livechat/sms-incoming/twilio
    • Method: POST

Test Cases

Test 1: MMS with Image (Primary Fix Validation)

  1. Send MMS with image attachment from phone to your Twilio number
  2. Open Omnichannel → Current Chats in Rocket.Chat
  3. Locate the conversation
  4. Verify:
    • Image displays correctly inline
    • Media URL appears in message text (e.g., https://api.twilio.com/.../Media/...)
    • No error message "An Attachment was received, but upload to server failed"
    • No FetchError in server logs
    • Image is clickable and opens full-size

Test 2: Regular SMS (Regression Test)

  1. Send plain SMS message (no attachments) to Twilio number
  2. Check Omnichannel conversation
  3. Verify:
    • Message appears correctly
    • No media URLs appended
    • No errors in logs
    • Conversation flow normal

Test 3: MMS with Video/Audio

  1. Send MMS with video or audio file
  2. Check conversation
  3. Verify:
    • Media displays with appropriate player
    • Media URL visible in message
    • File is downloadable

Expected Results

  • MMS attachments download successfully
  • All media types (images, videos, audio) display properly
  • Media URLs visible in message body
  • Regular SMS continues to work without changes
  • No "FetchError: redirect" errors in logs
  • Server logs show successful media fetch operations

Logs to Monitor

# Docker
docker logs -f <container_name> | grep SMS

# Look for successful media processing (should see these now):
# - "SMS" messages without "Attachment upload failed"
# - HTTP 200 responses for media fetches

Further comments

Community Validation

This fix has been validated by the original issue reporter (@sorscode) in a production Docker environment:

"After finally getting a new docker image to build correctly, I can confirm things work as expected now."

The issue was also confirmed by @alex-powell-1, indicating this affects multiple users.

Why This Solution?

Minimal, Focused Change:

  • Single-line fix to the core problem
  • Follows standard HTTP redirect handling practices
  • No architectural changes required

Safe Implementation:

  • Twilio URLs are trusted sources
  • SSRF check validates URLs before redirect following
  • fetch library handles redirect chains safely (prevents infinite loops)
  • File size and content type restrictions remain enforced

Standard Practice:

  • redirect: 'follow' is the default and recommended mode for fetch
  • Common pattern for CDN and media URLs that use redirects
  • Well-tested behavior in Node.js fetch implementations

Alternatives Considered

  1. Manual redirect handling: Could parse Location headers manually, but redirect: 'follow' is more robust and handles edge cases
  2. Pre-resolve URLs: Could try to get final URL from Twilio API first, but adds unnecessary complexity and API calls
  3. Different media handling: Could skip redirect entirely and link externally, but defeats purpose of storing media in Rocket.Chat

Additional Context

Why was redirect: 'error' used originally?

  • Likely a security precaution to prevent unintended redirects
  • However, with SSRF protection in place before the fetch, following redirects is safe
  • The SSRF check ensures we only fetch from valid, non-internal URLs

Impact:

  • Fixes MMS functionality for all Twilio users
  • Improves UX by showing media URLs in message text
  • Better debugging with enhanced error logging

Related:

  • Rocket.Chat docs state SMS is supported, not explicitly MMS
  • However, the code infrastructure for MMS exists, just had this redirect bug
  • This PR effectively enables a feature that was intended but broken

Checklist

  • I have read the Contributing Guide
  • I have signed the CLA
  • Lint and unit tests pass locally with my changes
  • I have added tests that prove my fix is effective or that my feature works (N/A - validated via community testing, requires live Twilio integration)
  • I have added necessary documentation (code comments added)
  • Any dependent changes have been merged and published in downstream modules (N/A - standalone fix)

Status: Ready for review and QA verification

Summary by CodeRabbit

  • Bug Fixes
    • Updated SMS media retrieval to follow redirects when fetching uploaded media.
    • Enhanced error logging with warnings on media fetch failures.
    • Media URLs now appended to SMS message bodies for improved visibility.

Changes fetch redirect mode from 'error' to 'follow' to handle Twilio's
302 redirects when downloading MMS media attachments. Also appends media
URLs to message body for better visibility.

- Modified getUploadFile() to follow redirects and added error logging
- Enhanced Twilio parse() to append media URLs to message text
- Maintains SSRF protection and backward compatibility

Resolves: RocketChat#36491
@ravi-aman ravi-aman requested review from a team as code owners November 4, 2025 13:47
@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Nov 4, 2025

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is missing the 'stat: QA assured' label
  • This PR is missing the required milestone or project

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link

changeset-bot bot commented Nov 4, 2025

⚠️ No Changeset found

Latest commit: e8a4a9d

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 4, 2025

Walkthrough

These changes address Twilio MMS inbound media retrieval failures by enabling HTTP redirects during media downloads and appending media URLs to message bodies. A warning log is added to capture fetch failures before throwing errors.

Changes

Cohort / File(s) Change Summary
Fetch redirect handling
apps/meteor/app/livechat/imports/server/rest/sms.ts
Changes fetch redirect policy from 'error' to 'follow' to allow HTTP redirects when retrieving Twilio media URLs; adds warning log on fetch failures (non-200 status or zero content size) before throwing invalid file error.
Twilio media URL post-processing
apps/meteor/server/services/omnichannel-integrations/providers/twilio.ts
Collects all media URLs from Twilio responses (skipping empty entries), joins them with newlines, and appends to the message body to ensure media links are visible alongside text content.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Verify the redirect policy change to 'follow' doesn't introduce unintended behavior or security concerns
  • Confirm media URL concatenation logic handles edge cases (empty arrays, malformed URLs)
  • Check that warning log statements provide sufficient debugging context

Poem

🐰 A hop, a skip, through Twilio's door,
Media redirects flow forevermore!
MMS blocked by strict rules of old,
Now links append with stories untold. ✨

Pre-merge checks and finishing touches

✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: Enable Twilio MMS inbound by following redirects' directly and clearly describes the main change: enabling Twilio MMS by following HTTP redirects instead of treating them as errors.
Linked Issues check ✅ Passed The PR successfully addresses all key objectives from issue #36491: enables redirect-following for Twilio media retrieval [#36491], preserves security controls with SSRF checks, maintains file size/content-type validation [#36491], adds diagnostic logging for failed fetches [#36491], and ensures backward compatibility for SMS [#36491].
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing Twilio MMS inbound handling: modifying fetch redirect policy in sms.ts, enhancing error logging, and appending media URLs to message body in twilio.ts. No unrelated changes detected.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/meteor/server/services/omnichannel-integrations/providers/twilio.ts (1)

102-110: LGTM! Media URLs appended for visibility.

The logic correctly collects and appends all non-empty media URLs to the message body, improving visibility of MMS content. The implementation properly handles edge cases (empty body, empty URLs, no media).

Note: The downstream handler in sms.ts (line 153) currently processes only the first media item for attachment upload, while this change displays all media URLs in the body. This means for multi-media messages, additional URLs will be visible to users but not automatically uploaded. Consider enhancing multi-media support in a future iteration.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between caa057f and a7cb0b7.

📒 Files selected for processing (2)
  • apps/meteor/app/livechat/imports/server/rest/sms.ts (1 hunks)
  • apps/meteor/server/services/omnichannel-integrations/providers/twilio.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-16T22:08:51.490Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-09-16T22:08:51.490Z
Learning: Applies to apps/meteor/tests/e2e/**/*.{ts,tsx,js,jsx} : Avoid code comments in the implementation

Applied to files:

  • apps/meteor/app/livechat/imports/server/rest/sms.ts
🔇 Additional comments (2)
apps/meteor/app/livechat/imports/server/rest/sms.ts (2)

36-37: LGTM! Redirect fix correctly addresses the Twilio MMS issue.

The change from redirect: 'error' to redirect: 'follow' properly enables retrieval of Twilio media URLs that return HTTP 302 redirects. Security is preserved since SSRF protection via checkUrlForSsrf() is enforced at lines 31-34 before the fetch executes, and the built-in fetch API prevents infinite redirect loops.


44-44: LGTM! Improved diagnostics for fetch failures.

The warning log captures essential debugging information (URL, HTTP status, content size) before throwing the error, making it easier to diagnose media retrieval issues.

@sorscode
Copy link

sorscode commented Nov 4, 2025

Appreciate you doing the PR on this, I never got around to doing one.

@ravi-aman
Copy link
Author

Hello maintainers,

I opened PR #37376{ which fixes Twilio MMS inbound redirects (a long-standing issue affecting multiple community users).

The PR is ready, tested, and has been validated by issue reporters, but no code owner has reviewed it yet.

Could someone point me to the right maintainer or help get a review?

Thank you!

@bionemesis
Copy link

Any update on this? We'd love to see this implemented.

@sorscode
Copy link

I know the branch is behind and needs updated, but once that is done again, what would it take to get this into the main branch?

Copilot AI review requested due to automatic review settings January 11, 2026 19:07
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes Twilio MMS inbound functionality by enabling HTTP redirect following when fetching media attachments. When customers send MMS messages through Twilio, media URLs respond with HTTP 302 redirects to the actual media location. The previous implementation rejected all redirects, causing MMS attachments to fail.

Changes:

  • Modified fetch behavior to follow redirects for Twilio media URLs
  • Added media URLs to message body for improved visibility
  • Enhanced error logging with URL, status code, and content size

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
apps/meteor/app/livechat/imports/server/rest/sms.ts Changed fetch redirect mode from 'error' to 'follow' and improved error logging
apps/meteor/server/services/omnichannel-integrations/providers/twilio.ts Added logic to append media URLs to message body for better visibility

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@ravi-aman
Copy link
Author

I’ve updated the branch with the latest develop and all checks are passing — just wanted to confirm if anything else is needed from my side, or if this is now waiting on maintainer/code owner approval.

@sorscode
Copy link

Like to see this get put in soon, so we can move back to normal deployments of Rocket.Chat. Currently running self-built versions breaks Push Notifications, which is ultra annoying.

const contentSize = content.length;

if (response.status !== 200 || contentSize === 0) {
logger.warn(`Failed to fetch file from ${fileUrl}: status ${response.status}, size ${contentSize}`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you really want to have this log, change it to be an object instead of templates

logger.error({ msg: 'Failed to fetch file', fileUrl, status: response.status, contentSize });

Comment on lines +102 to +111
// Append media URLs to the message body for better visibility
if (returnData.media.length > 0) {
const links = returnData.media
.map((media) => media.url)
.filter((url) => !!url) // skip empty URLs
.join('\n');

returnData.body = [returnData.body, links].filter(Boolean).join('\n');
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this.

Suggested change
// Append media URLs to the message body for better visibility
if (returnData.media.length > 0) {
const links = returnData.media
.map((media) => media.url)
.filter((url) => !!url) // skip empty URLs
.join('\n');
returnData.body = [returnData.body, links].filter(Boolean).join('\n');
}

@KevLehman
Copy link
Member

I'll put this PR on hold for now, there's internal work to address this issue with a more secure PoV.

#38044

@KevLehman KevLehman self-assigned this Jan 14, 2026
@ravi-aman
Copy link
Author

Thanks for the feedback @KevLehman
Understood on both points.

Given that this PR is now on hold in favor of #38044,
I’ll wait for further direction and am happy to adjust
this PR or help with the new approach if needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Twilio MMS Inbound not working

4 participants