Sms Import / Export currently implements a rudimentary but powerful mechanism for filtering messages when exporting, wiping, or counting them. In order to use this mechanism effectively, it is important to understand how Android stores messages internally and how SMS I/E accesses them.
Android stores both SMS and MMS messages in an SQLite database. For SMS messages, a single table contains both the message data (in the body column) and all its metadata (in various other columns). (The name of the other party to the message is not stored in the message table, since a message contains only an "address" (phone number) but not any sort of contact name. Android associates a name with the message via user provided contact information, and this information is stored in a different database.)
For MMS messages, however, the situation is more complicated. The main MMS message table contains most of the message metadata (including the dates the message was sent and received in the date_sent and date columns (present in the SMS message table as well) respectively), but not the sender and recipient "addresses" or the actual message data ("parts," both text and binary), which are stored in different tables.
Android provides a ContentProvider API for accessing SMS and MMS messages, which functions as a thin abstraction layer over the underlying SQLite API. Due to the previously described internal message storage architecture, when exporting SMS messages, SMS I/E issues a single query to retrieve all data and metadata of all messages (except for the contact names of the messages' other parties, which requires additional queries since they are stored in a separate database, as above). When exporting MMS messages, however, SMS I/E initially issues a single query to retrieve the message metadata (of all messages) that is stored in the main MMS table, but then issues additional queries for each message to retrieve its sender and recipient "addresses" and its "parts."
The current message filtering mechanism is implemented by constructing an SQLite WHERE clause out of user-specified filters, which is used with the queries of the main SMS and MMS tables. Consequently, SMS messages can be filtered based on their data and (in principle) any of their metadata, whereas MMS messages can be filtered based only on their metadata that is present in the main MMS table.
Similarly, when wiping or counting messages SMS I/E issues one delete or query command to the SMS table and one to the MMS table, both of which are filtered in the same way as queries issued when exporting messages are.
To use message filtering, it must be enabled in the app's Settings, and one or more filters must be configured (and set to Active) using the Message Filtering interface. When an export (manual or scheduled) or wipe is executed, the app will combine all active filters using the SQLite AND keyword and use the result as an SQLite WHERE clause. (A filter that is not currently desired but may be desired in the future can be set to Inactive rather than deleted in order to avoid having to reconfigure it later.)
Note Even filters that are marked Active will not be used if Message Filtering is not enabled in the app's Settings.
Message filters have three fields:
Column name: the name of an Android SMS or MMS column (these columns are documented here: SMS, [MMS)(https://developer.android.com/reference/android/provider/Telephony.BaseMmsColumns)). If the name is prefixed bysms.ormms., then this filter will be used only when querying the SMS or MMS table respectively (since the column in question is only present in the respective table).Operator: an SQLite operator (these are officially documented here, and somewhat more readably here).Column value: a user-provided value.
Column names and operators are chosen from drop-down lists provided by the app; column values are entered by the user. All column values are used exactly as entered, with the exception of dates, as discussed in the following section.
[!WARNING] The app does not perform any syntax checking of provided column values, and it is the user's responsibility to ensure that the configured filter constitutes valid SQLite syntax. If it does not, subsequent exports, wipes, and counts will fail with
SQLiteExceptions. The app also does not currently implement parameter substitution in itsContentProvidercalls, and so the message filtering framework is technically susceptible to [SQL injection]. This should not generally be a significant vulnerability, though, since message filters must be explicitly configured by the user.
Dates (i.e., values for columns date and date_sent) can currently be specified in four formats:
- If the value contains the letter 'T' (upper or lower case), it is assumed to be a Java / Kotlin instant (and must contain at least 16 characters, not including the initial year digits [i.e., at least -MM-DDTHH:MM:SSZ]). E.g.: '2026-04-20T05:30:00Z'.
- If it does not contain 'T' but does contain a hyphen ('-'), it is assumed to be an ISO 8601 style date in the format
yyyy-MM-dd. E.g.: '2026-04-20'. - If it contains neither 'T' nor '-' and is 11 or fewer characters, it is assumed to be in Unix time, in seconds since the epoch. E.g.: '1776657600'.
- If none of the above hold, it is assumed to be in milliseconds since the epoch. E.g.: '1776657600000'.
For some mysterious reason, Android stores SMS timestamps in milliseconds since the epoch, and MMS timestamps in seconds since the epoch. Internally, SMS I/E initially converts all the above date formats to milliseconds since the epoch. Subsequently, if the date is being used in an SMS query, it is used as is, and if it's being used in an MMS query, it's converted to seconds since the epoch.
(To convert between Unix time and human readable dates, use (on Unix-like systems) date -d'@<unix_time>' / date -d<human_readable_date> +%s, or use an online converter such as this one.)
Note: The date conversion routines will not currently work correctly on values that contain multiple dates, so the BETWEEN and IN operators should not be used with dates. (BETWEEN date1 AND date2 can be simply rewritten as the two filters >= date1 and <= date2.)
Following are some examples of message filter lists and the resulting message selections:
| Column name | Operator | Column value |
|---|---|---|
| date_sent | BETWEEN | 1735689600000 AND 1735775999000 |
all SMS and MMS messages sent between Wednesday, January 1, 2025 12:00:00 AM and Wednesday, January 1, 2025 11:59:59 PM (GMT, inclusive).
| Column name | Operator | Column value |
|---|---|---|
| date | > | 1735689600000 |
| sms.body | LIKE | '%Thanks%' |
all SMS messages sent after Wednesday, January 1, 2025 12:00:00 AM whose bodies contain the string "Thanks", and all MMS messages sent after that time. Be sure to include the single quotes around the column value, since SQLite string literals must be surrounded by quotes. When using the LIKE operator, the default SQLite case-sensitivity semantics are used.
| Column name | Operator | Column value |
|---|---|---|
| sms.type | == | 1 |
| mms.msg_box | == | 1 |
all received (as opposed to sent) SMS and MMS messages. (For the meaning of the various possible values for sms.type and mms.msg_box, see here and here respectively.)