# How SmsForwarder Implements MMS Message Handling and Parsing in Android

> Discover how SmsForwarder handles MMS messages by registering broadcast receivers, decoding message parts like text and images using Java reflection, and merging them for forwarding. Learn the technical implementation.

- Repository: [pppscn/SmsForwarder](https://github.com/pppscn/SmsForwarder)
- Tags: internals
- Published: 2026-06-22

---

**SmsForwarder handles MMS messages by registering a broadcast receiver for WAP push intents, extracting the raw PDU byte array, and using Java reflection to decode message parts—including text and images—before merging them into a unified message for forwarding.**

The SmsForwarder open-source project (pppscn/SmsForwarder) provides a robust solution for automatically forwarding SMS and MMS messages to various channels. Understanding how it implements MMS message handling and parsing reveals a clever use of reflection to access Android's internal MMS APIs, allowing the extraction of multimedia content without relying on undocumented public methods.

## Broadcast Reception and Intent Filtering

The MMS handling pipeline begins in [`app/src/main/kotlin/cn/ppps/forwarder/receiver/SmsReceiver.kt`](https://github.com/pppscn/SmsForwarder/blob/main/app/src/main/kotlin/cn/ppps/forwarder/receiver/SmsReceiver.kt), where the receiver listens for system WAP push broadcasts. Specifically, the receiver registers for `WAP_PUSH_RECEIVED_ACTION` and `WAP_PUSH_DELIVER_ACTION` intents at lines 42-44.

When the Android system receives an MMS, it broadcasts these intents containing the raw Protocol Data Unit (PDU). The receiver must be declared in the manifest with appropriate permissions to intercept these system-level broadcasts.

## Validating MMS Intents

Before processing, SmsForwarder validates that the incoming intent actually represents an MMS message. At lines 45-48, the code performs two critical checks:

- The intent's type must equal `application/vnd.wap.mms-message`
- The `transactionId` extra must equal `"mms"`

This validation ensures the receiver only processes genuine MMS payloads and ignores other WAP push notifications that might use different MIME types.

## Extracting Raw MMS Data

Once validated, the receiver extracts the raw byte payload at lines 49-51. The code retrieves the byte array extra named `"data"` from the intent, which contains the complete MMS PDU. This raw data is then passed to the `handleMmsData` method for parsing and content extraction.

## Reflection-Based MMS Decoding

The core MMS parsing logic resides in the `handleMmsData` method within [`SmsReceiver.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SmsReceiver.kt). Since Android does not expose public APIs for parsing MMS PDUs directly, SmsForwarder uses reflection to access internal telephony classes.

At lines 50-57, the implementation loads `android.telephony.gsm.SmsMessage` via `Class.forName()` and invokes the `createFromPdu(byte[])` method to obtain a message object. This approach allows the app to decode the binary MMS structure without requiring private API access or platform-specific dependencies.

After obtaining the message object, the code calls `getParts()` at lines 63-64 to retrieve an array of individual MMS parts. Each part represents a segment of the multimedia message, such as text, images, or attachments.

### Parsing Text Content

For text extraction, the parser iterates through each part and checks the content type at lines 66-68. When `getContentType()` returns `text/plain`, the code extracts the payload using `getData()` at lines 70-77 and appends the text to the message string (`msg`). This allows SmsForwarder to capture the textual content of MMS messages alongside traditional SMS.

### Handling Image Parts

Binary content such as images follows a similar extraction pattern. At lines 81-86, the code retrieves image data using `getData()`, though the current implementation treats this as a placeholder for custom handling. The binary data is available for extension, allowing developers to implement image saving or base64 encoding for forwarding services that support multimedia attachments.

## Forwarding Parsed Content

After parsing completes, the combined message content—now containing both SMS text and any extracted MMS text—is wrapped in a `MsgInfo` object. At lines 109-117, this object is dispatched to `SendWorker` for processing through the configured forwarding channels (webhooks, email, Telegram, etc.).

This architecture ensures that MMS content flows through the same forwarding pipeline as regular SMS, maintaining consistency across all message types.

## Required Permissions

To receive MMS broadcasts, the application must declare the appropriate permission in [`app/src/main/AndroidManifest.xml`](https://github.com/pppscn/SmsForwarder/blob/main/app/src/main/AndroidManifest.xml). Line 38 contains the required declaration:

```xml
<uses-permission android:name="android.permission.RECEIVE_MMS" />

```

Without this permission, the system will not deliver WAP push broadcasts to the application, preventing any MMS processing regardless of the receiver implementation.

## Implementation Example

Developers can extend SmsForwarder's approach using the following reflection pattern. This snippet mirrors the library's implementation for extracting text from MMS parts:

```kotlin
// Inside SmsReceiver.handleMmsData()
val mmsClass = Class.forName("android.telephony.gsm.SmsMessage")
val createFromPdu = mmsClass.getDeclaredMethod("createFromPdu", ByteArray::class.java)
val message = createFromPdu.invoke(null, data) ?: return

val parts = message.javaClass.getMethod("getParts")
    .invoke(message) as? Array<*>
parts?.forEach { part ->
    val type = part?.javaClass?.getMethod("getContentType")
        ?.invoke(part) as? String

    if (type?.startsWith("text/plain") == true) {
        val text = part.javaClass.getMethod("getData")
            .invoke(part) as? String
        text?.let { Log.d(TAG, "MMS Text: $it") }
    }
    // Image handling omitted for brevity
}

```

This code demonstrates how to hook into the same reflection-based parsing used by SmsForwarder, enabling custom processing of MMS content types beyond the default text extraction.

## Summary

- **MMS Handling Pipeline**: SmsForwarder intercepts WAP push broadcasts via [`SmsReceiver.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SmsReceiver.kt) and validates MIME types before processing.
- **Reflection-Based Parsing**: The app uses `Class.forName()` to access `android.telephony.gsm.SmsMessage` and decode PDU byte arrays without private API dependencies.
- **Content Extraction**: Text parts are extracted via `getData()` when `getContentType()` matches `text/plain`, while image data is available for custom extensions.
- **Unified Forwarding**: Parsed MMS content merges into the standard `Msg` flow before dispatch to `SendWorker` for channel-specific forwarding.
- **Permission Requirements**: `RECEIVE_MMS` must be declared in [`AndroidManifest.xml`](https://github.com/pppscn/SmsForwarder/blob/main/AndroidManifest.xml) to receive system MMS broadcasts.

## Frequently Asked Questions

### Why does SmsForwarder use reflection for MMS parsing instead of standard Android APIs?

Android does not expose public APIs for parsing MMS PDU (Protocol Data Unit) data directly. The `android.telephony.gsm.SmsMessage` class contains the necessary decoding logic, but it is marked as internal or hidden in the SDK. SmsForwarder uses reflection to invoke `createFromPdu()` and `getParts()` at runtime, allowing the app to extract multimedia content without requiring platform-specific modifications or private API access that would trigger Google Play restrictions.

### What specific MIME type does SmsForwarder check for when handling MMS messages?

According to the source code in [`SmsReceiver.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SmsReceiver.kt) at lines 45-48, SmsForwarder validates that the intent type equals `application/vnd.wap.mms-message`. This MIME type identifies WAP push messages containing MMS data as defined by the Open Mobile Alliance standards. The code also verifies that the intent's `transactionId` equals `"mms"` to ensure it processes only MMS-specific broadcasts rather than other WAP push notifications.

### How does SmsForwarder handle image attachments in MMS messages?

The current implementation in [`SmsReceiver.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SmsReceiver.kt) (lines 81-86) extracts binary image data using the same reflection-based `getData()` method used for text, but treats it as a placeholder for custom handling. While text content is automatically appended to the forwarding message, image processing requires extending the `forEach` loop to implement base64 encoding, file saving, or direct upload to forwarding channels. The binary data is available through the reflection API for developers who need multimedia forwarding capabilities.

### What permission is required to receive MMS broadcasts in SmsForwarder?

The app must declare `android.permission.RECEIVE_MMS` in [`app/src/main/AndroidManifest.xml`](https://github.com/pppscn/SmsForwarder/blob/main/app/src/main/AndroidManifest.xml) (line 38). This permission allows the application to receive system broadcasts when new MMS messages arrive via WAP push. Without this declaration, the `SmsReceiver` will not receive the `WAP_PUSH_RECEIVED_ACTION` or `WAP_PUSH_DELIVER_ACTION` intents, making MMS forwarding impossible regardless of the parsing implementation.