[android] How to delete an SMS from the inbox in Android programmatically?

On Android phones SMS messages registered to applications also get sent to the device's inbox. However to prevent clutter, it'd be nice to be able to remove application specific SMS messages from the inbox to reduce the potential overflow of those messages.

Questions on other Google groups on getting a definitive answer on a programmatic way to delete SMS messages from the Android inbox don't seem to be pressing.

So the scenario:

  • Android App startup.
  • register SMS message types X,Y and Z
  • messages P,Q,X,Y,Z stream in over the course of time, all deposited in inbox
  • Android application detects receipt of X,Y,Z (presumably as part of the program interrupt event)
  • process X,Y,Z
  • Desirement!!! X,Y,Z are deleted from the Android inbox

Has it been done? Can it be done?

This question is related to android sms

The answer is


Sample for deleting one SMS, not conversation:

getContentResolver().delete(Uri.parse("content://sms/conversations/" + threadID), "_id = ?", new String[]{id});

You just try the following code.It will delete all the sms that are all in phone (Received or Sent)

Uri uri = Uri.parse("content://sms");

ContentResolver contentResolver = getContentResolver();

Cursor cursor = contentResolver.query(uri, null, null, null,
  null);



while (cursor.moveToNext()) {

 long thread_id = cursor.getLong(1);
 Uri thread = Uri.parse("content://sms/conversations/"
   + thread_id);
 getContentResolver().delete(thread, null, null);
}

Also update the manifest file as to delete an sms you need write permissions.

<uses-permission android:name="android.permission.WRITE_SMS"/>

@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
    SMSData sms = (SMSData) getListAdapter().getItem(position);
    Toast.makeText(getApplicationContext(), sms.getBody(),
            Toast.LENGTH_LONG).show();
    Toast.makeText(getApplicationContext(), sms.getNumber(),
            Toast.LENGTH_LONG).show();

    deleteSms(sms.getId());

}

public boolean deleteSms(String smsId) {
    boolean isSmsDeleted = false;
    try {
        MainActivity.this.getContentResolver().delete(
                Uri.parse("content://sms/" + smsId), null, null);
        isSmsDeleted = true;

    } catch (Exception ex) {
        isSmsDeleted = false;
    }
    return isSmsDeleted;
}

Also update the manifest file as to delete an sms you need write permissions.

<uses-permission android:name="android.permission.WRITE_SMS"/>

So, I had a play, and it is possible to delete a received SMS. Unfortunately it's not all plain sailing :(

I have a receiver that picks up on incoming SMS messages. Now the way the Android SMS incoming routing works is that the piece of code responsible for decoding the messages sends a Broadcast (it uses the sendBroadcast() method - which unfortunately is NOT the version that lets you simply call abortBroadcast()) whenever a message arrives.

My receiver may or may not be called before the Systems SMS receiver, and in any case the received broadcast has no property that could reflect the _id column in the SMS table.

However, not being one to be stopped that easily I post myself (via a Handler) a delayed message with the SmsMessage as the attached object. (I suppose you could post yourself a Runnable too...)

handler.sendMessageDelayed(handler.obtainMessage(MSG_DELETE_SMS, msg), 2500);

The delay is there to ensure that by the time the message arrives all of the Broadcast receivers will have finished their stuff and the message will be safely ensconced in the SMS table.

When the message (or Runnable) is received here is what I do:

case MSG_DELETE_SMS:
    Uri deleteUri = Uri.parse("content://sms");
    SmsMessage msg = (SmsMessage)message.obj;

    getContentResolver().delete(deleteUri, "address=? and date=?", new String[] {msg.getOriginatingAddress(), String.valueOf(msg.getTimestampMillis())});

I use the originating address and timestamp field to ensure a very high probability of deleting ONLY the message I am interested in. If I wanted to be even more paranoid I could include the msg.getMessageBody() content as part of the query.

Yes, the message IS deleted (hooray!). Unfortunately the notification bar is not updated :(

When you open up the notification area you'll see the message sitting there for you... but when you tap on it to open it up - it's gone!

To me, this isn't quite good enough - I want all trace of the message to disappear - I don't want the user to think there is a TXT when there isn't (that would only cause bug reports).

Internally in the OS the phone calls MessagingNotification.updateNewMessageIndicator(Context), but I that class has been hidden from the API, and I did not want to replicate all of that code just for the sake of making the indicator accurate.


You'll need to find the URI of the message. But once you do I think you should be able to android.content.ContentResolver.delete(...) it.

Here's some more info.


Use one of this method to select the last received SMS and delete it, here in this case i am getting the top most sms and going to delete using thread and id value of sms,

try {
    Uri uri = Uri.parse("content://sms/inbox");
    Cursor c = v.getContext().getContentResolver().query(uri, null, null, null, null);
    int i = c.getCount();

    if (c.moveToFirst()) {
    }
} catch (CursorIndexOutOfBoundsException ee) {
    Toast.makeText(v.getContext(), "Error :" + ee.getMessage(), Toast.LENGTH_LONG).show();
}

@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
    SMSData sms = (SMSData) getListAdapter().getItem(position);
    Toast.makeText(getApplicationContext(), sms.getBody(),
            Toast.LENGTH_LONG).show();
    Toast.makeText(getApplicationContext(), sms.getNumber(),
            Toast.LENGTH_LONG).show();

    deleteSms(sms.getId());

}

public boolean deleteSms(String smsId) {
    boolean isSmsDeleted = false;
    try {
        MainActivity.this.getContentResolver().delete(
                Uri.parse("content://sms/" + smsId), null, null);
        isSmsDeleted = true;

    } catch (Exception ex) {
        isSmsDeleted = false;
    }
    return isSmsDeleted;
}

Using suggestions from others, I think I got it to work:

(using SDK v1 R2)

It's not perfect, since i need to delete the entire conversation, but for our purposes, it's a sufficient compromise as we will at least know all messages will be looked at and verified. Our flow will probably need to then listen for the message, capture for the message we want, do a query to get the thread_id of the recently inbounded message and do the delete() call.

In our Activity:

Uri uriSms = Uri.parse("content://sms/inbox");
Cursor c = getContentResolver().query(uriSms, null,null,null,null); 
int id = c.getInt(0);
int thread_id = c.getInt(1); //get the thread_id
getContentResolver().delete(Uri.parse("content://sms/conversations/" + thread_id),null,null);

Note: I wasn't able to do a delete on content://sms/inbox/ or content://sms/all/

Looks like the thread takes precedence, which makes sense, but the error message only emboldened me to be angrier. When trying the delete on sms/inbox/ or sms/all/, you will probably get:

java.lang.IllegalArgumentException: Unknown URL
    at com.android.providers.telephony.SmsProvider.delete(SmsProvider.java:510)
    at android.content.ContentProvider$Transport.delete(ContentProvider.java:149)
    at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:149)

For additional reference too, make sure to put this into your manifest for your intent receiver:

<receiver android:name=".intent.MySmsReceiver">
    <intent-filter>
        <action android:name="android.provider.Telephony.SMS_RECEIVED"></action>
    </intent-filter>
</receiver>

Note the receiver tag does not look like this:

<receiver android:name=".intent.MySmsReceiver" 
    android:permission="android.permission.RECEIVE_SMS">

When I had those settings, android gave me some crazy permissions exceptions that didn't allow android.phone to hand off the received SMS to my intent. So, DO NOT put that RECEIVE_SMS permission attribute in your intent! Hopefully someone wiser than me can tell me why that was the case.


Try this i am 100% sure this will work fine:- //just put conversion address here for delete whole conversion by address(don't forgot to add read,write permission in mainfest) Here is Code:

String address="put address only";

Cursor c = getApplicationContext().getContentResolver().query(Uri.parse("content://sms/"), new String[] { "_id", "thread_id", "address", "person", "date", "body" }, null, null, null);

try {
    while (c.moveToNext()) {
        int id = c.getInt(0);
        String address = c.getString(2);
        if(address.equals(address)){
        getApplicationContext().getContentResolver().delete(Uri.parse("content://sms/" + id), null, null);}
    }
} catch(Exception e) {

}

public boolean deleteSms(String smsId) {
    boolean isSmsDeleted = false;
    try {
        mActivity.getContentResolver().delete(Uri.parse("content://sms/" + smsId), null, null);
        isSmsDeleted = true;

    } catch (Exception ex) {
        isSmsDeleted = false;
    }
    return isSmsDeleted;
}

use this permission in AndroidManifiest

<uses-permission android:name="android.permission.WRITE_SMS"/>

I think this can not be perfectly done for the time being. There are 2 basic problems:

  1. How can you make sure the sms is already in the inbox when you try to delete it?
    Notice that SMS_RECEIVED is not an ordered broadcast.
    So dmyung's solution is completely trying one's luck; even the delay in Doug's answer is not a guarantee.

  2. The SmsProvider is not thread safe.(refer to http://code.google.com/p/android/issues/detail?id=2916#c0)
    The fact that more than one clients are requesting delete and insert in it at the same time will cause data corruption or even immediate Runtime Exception.


You just try the following code.It will delete all the sms that are all in phone (Received or Sent)

Uri uri = Uri.parse("content://sms");

ContentResolver contentResolver = getContentResolver();

Cursor cursor = contentResolver.query(uri, null, null, null,
  null);



while (cursor.moveToNext()) {

 long thread_id = cursor.getLong(1);
 Uri thread = Uri.parse("content://sms/conversations/"
   + thread_id);
 getContentResolver().delete(thread, null, null);
}

Its better to use the _id and thread_id to delete a message.

Thread_id is something assigned to the messages coming from same user. So, if you use only thread_id, all the messages from the sender will get deleted.

If u use the combination of _id, thread_id, then it will delete the exact message you are looking to delete.

Uri thread = Uri.parse( "content://sms");
int deleted = contentResolver.delete( thread, "thread_id=? and _id=?", new String[]{String.valueOf(thread_id), String.valueOf(id)} );

You'll need to find the URI of the message. But once you do I think you should be able to android.content.ContentResolver.delete(...) it.

Here's some more info.


I couldn't get it to work using dmyung's solution, it gave me an exception when getting either the message id or thread id.

In the end, I've used the following method to get the thread id:

private long getThreadId(Context context) {
    long threadId = 0;

    String SMS_READ_COLUMN = "read";
    String WHERE_CONDITION = SMS_READ_COLUMN + " = 0";
    String SORT_ORDER = "date DESC";
    int count = 0;

    Cursor cursor = context.getContentResolver().query(
                    SMS_INBOX_CONTENT_URI,
          new String[] { "_id", "thread_id", "address", "person", "date", "body" },
                    WHERE_CONDITION,
                    null,
                    SORT_ORDER);

    if (cursor != null) {
            try {
                count = cursor.getCount();
                if (count > 0) {
                    cursor.moveToFirst();
                    threadId = cursor.getLong(1);                              
                }
            } finally {
                    cursor.close();
            }
    }


    return threadId;
}

Then I could delete it. However, as Doug said, the notification is still there, even the message is displayed when opening the notification panel. Only when tapping the message I could actually see that it's empty.

So I guess the only way this would work would be to actually somehow intercept the SMS before it's delivered to the system, before it even reaches the inbox. However, I highly doubt this is doable. Please correct me if I'm wrong.


Now abortBroadcast(); method can be used for restricting the incoming message to go to inbox.


Just turn off notifications for the default sms app. Process your own notifications for all text messages!


You'll need to find the URI of the message. But once you do I think you should be able to android.content.ContentResolver.delete(...) it.

Here's some more info.


Now abortBroadcast(); method can be used for restricting the incoming message to go to inbox.


Use one of this method to select the last received SMS and delete it, here in this case i am getting the top most sms and going to delete using thread and id value of sms,

try {
    Uri uri = Uri.parse("content://sms/inbox");
    Cursor c = v.getContext().getContentResolver().query(uri, null, null, null, null);
    int i = c.getCount();

    if (c.moveToFirst()) {
    }
} catch (CursorIndexOutOfBoundsException ee) {
    Toast.makeText(v.getContext(), "Error :" + ee.getMessage(), Toast.LENGTH_LONG).show();
}

Its better to use the _id and thread_id to delete a message.

Thread_id is something assigned to the messages coming from same user. So, if you use only thread_id, all the messages from the sender will get deleted.

If u use the combination of _id, thread_id, then it will delete the exact message you are looking to delete.

Uri thread = Uri.parse( "content://sms");
int deleted = contentResolver.delete( thread, "thread_id=? and _id=?", new String[]{String.valueOf(thread_id), String.valueOf(id)} );

Just have a look at this link, it will give you a brief idea of the logic:

https://gist.github.com/5178e798d9a00cac4ddb
Just call the deleteSMS() function with some delay, because there is a slight difference between the time of notification and when it is saved actually...., for details have a look at this link also..........

http://htmlcoderhelper.com/how-to-delete-sms-from-inbox-in-android-programmatically/

Thanks..........


Using suggestions from others, I think I got it to work:

(using SDK v1 R2)

It's not perfect, since i need to delete the entire conversation, but for our purposes, it's a sufficient compromise as we will at least know all messages will be looked at and verified. Our flow will probably need to then listen for the message, capture for the message we want, do a query to get the thread_id of the recently inbounded message and do the delete() call.

In our Activity:

Uri uriSms = Uri.parse("content://sms/inbox");
Cursor c = getContentResolver().query(uriSms, null,null,null,null); 
int id = c.getInt(0);
int thread_id = c.getInt(1); //get the thread_id
getContentResolver().delete(Uri.parse("content://sms/conversations/" + thread_id),null,null);

Note: I wasn't able to do a delete on content://sms/inbox/ or content://sms/all/

Looks like the thread takes precedence, which makes sense, but the error message only emboldened me to be angrier. When trying the delete on sms/inbox/ or sms/all/, you will probably get:

java.lang.IllegalArgumentException: Unknown URL
    at com.android.providers.telephony.SmsProvider.delete(SmsProvider.java:510)
    at android.content.ContentProvider$Transport.delete(ContentProvider.java:149)
    at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:149)

For additional reference too, make sure to put this into your manifest for your intent receiver:

<receiver android:name=".intent.MySmsReceiver">
    <intent-filter>
        <action android:name="android.provider.Telephony.SMS_RECEIVED"></action>
    </intent-filter>
</receiver>

Note the receiver tag does not look like this:

<receiver android:name=".intent.MySmsReceiver" 
    android:permission="android.permission.RECEIVE_SMS">

When I had those settings, android gave me some crazy permissions exceptions that didn't allow android.phone to hand off the received SMS to my intent. So, DO NOT put that RECEIVE_SMS permission attribute in your intent! Hopefully someone wiser than me can tell me why that was the case.


Try this i am 100% sure this will work fine:- //just put conversion address here for delete whole conversion by address(don't forgot to add read,write permission in mainfest) Here is Code:

String address="put address only";

Cursor c = getApplicationContext().getContentResolver().query(Uri.parse("content://sms/"), new String[] { "_id", "thread_id", "address", "person", "date", "body" }, null, null, null);

try {
    while (c.moveToNext()) {
        int id = c.getInt(0);
        String address = c.getString(2);
        if(address.equals(address)){
        getApplicationContext().getContentResolver().delete(Uri.parse("content://sms/" + id), null, null);}
    }
} catch(Exception e) {

}

Use this function to delete specific message thread or modify according your needs:

public void delete_thread(String thread) 
{ 
  Cursor c = getApplicationContext().getContentResolver().query(
  Uri.parse("content://sms/"),new String[] { 
  "_id", "thread_id", "address", "person", "date","body" }, null, null, null);

 try {
  while (c.moveToNext()) 
      {
    int id = c.getInt(0);
    String address = c.getString(2);
    if (address.equals(thread)) 
        {
     getApplicationContext().getContentResolver().delete(
     Uri.parse("content://sms/" + id), null, null);
    }

       }
} catch (Exception e) {

  }
}

Call this function simply below:

delete_thread("54263726");//you can pass any number or thread id here

Don't forget to add android mainfest permission below:

<uses-permission android:name="android.permission.WRITE_SMS"/>

"As of Android 1.6, incoming SMS message broadcasts (android.provider.Telephony.SMS_RECEIVED) are delivered as an "ordered broadcast" — meaning that you can tell the system which components should receive the broadcast first."

This means that you can intercept incoming message and abort broadcasting of it further on.

In your AndroidManifest.xml file, make sure to have priority set to highest:

<receiver android:name=".receiver.SMSReceiver" android:enabled="true">
    <intent-filter android:priority="1000">
        <action android:name="android.provider.Telephony.SMS_RECEIVED" />
    </intent-filter>
</receiver>

In your BroadcastReceiver, in onReceive() method, before performing anything with your message, simply call abortBroadcast();

EDIT: As of KitKat, this doesn't work anymore apparently.

EDIT2: More info on how to do it on KitKat here:

Delete SMS from android on 4.4.4 (Affected rows = 0(Zero), after deleted)


Sample for deleting one SMS, not conversation:

getContentResolver().delete(Uri.parse("content://sms/conversations/" + threadID), "_id = ?", new String[]{id});

Using suggestions from others, I think I got it to work:

(using SDK v1 R2)

It's not perfect, since i need to delete the entire conversation, but for our purposes, it's a sufficient compromise as we will at least know all messages will be looked at and verified. Our flow will probably need to then listen for the message, capture for the message we want, do a query to get the thread_id of the recently inbounded message and do the delete() call.

In our Activity:

Uri uriSms = Uri.parse("content://sms/inbox");
Cursor c = getContentResolver().query(uriSms, null,null,null,null); 
int id = c.getInt(0);
int thread_id = c.getInt(1); //get the thread_id
getContentResolver().delete(Uri.parse("content://sms/conversations/" + thread_id),null,null);

Note: I wasn't able to do a delete on content://sms/inbox/ or content://sms/all/

Looks like the thread takes precedence, which makes sense, but the error message only emboldened me to be angrier. When trying the delete on sms/inbox/ or sms/all/, you will probably get:

java.lang.IllegalArgumentException: Unknown URL
    at com.android.providers.telephony.SmsProvider.delete(SmsProvider.java:510)
    at android.content.ContentProvider$Transport.delete(ContentProvider.java:149)
    at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:149)

For additional reference too, make sure to put this into your manifest for your intent receiver:

<receiver android:name=".intent.MySmsReceiver">
    <intent-filter>
        <action android:name="android.provider.Telephony.SMS_RECEIVED"></action>
    </intent-filter>
</receiver>

Note the receiver tag does not look like this:

<receiver android:name=".intent.MySmsReceiver" 
    android:permission="android.permission.RECEIVE_SMS">

When I had those settings, android gave me some crazy permissions exceptions that didn't allow android.phone to hand off the received SMS to my intent. So, DO NOT put that RECEIVE_SMS permission attribute in your intent! Hopefully someone wiser than me can tell me why that was the case.


So, I had a play, and it is possible to delete a received SMS. Unfortunately it's not all plain sailing :(

I have a receiver that picks up on incoming SMS messages. Now the way the Android SMS incoming routing works is that the piece of code responsible for decoding the messages sends a Broadcast (it uses the sendBroadcast() method - which unfortunately is NOT the version that lets you simply call abortBroadcast()) whenever a message arrives.

My receiver may or may not be called before the Systems SMS receiver, and in any case the received broadcast has no property that could reflect the _id column in the SMS table.

However, not being one to be stopped that easily I post myself (via a Handler) a delayed message with the SmsMessage as the attached object. (I suppose you could post yourself a Runnable too...)

handler.sendMessageDelayed(handler.obtainMessage(MSG_DELETE_SMS, msg), 2500);

The delay is there to ensure that by the time the message arrives all of the Broadcast receivers will have finished their stuff and the message will be safely ensconced in the SMS table.

When the message (or Runnable) is received here is what I do:

case MSG_DELETE_SMS:
    Uri deleteUri = Uri.parse("content://sms");
    SmsMessage msg = (SmsMessage)message.obj;

    getContentResolver().delete(deleteUri, "address=? and date=?", new String[] {msg.getOriginatingAddress(), String.valueOf(msg.getTimestampMillis())});

I use the originating address and timestamp field to ensure a very high probability of deleting ONLY the message I am interested in. If I wanted to be even more paranoid I could include the msg.getMessageBody() content as part of the query.

Yes, the message IS deleted (hooray!). Unfortunately the notification bar is not updated :(

When you open up the notification area you'll see the message sitting there for you... but when you tap on it to open it up - it's gone!

To me, this isn't quite good enough - I want all trace of the message to disappear - I don't want the user to think there is a TXT when there isn't (that would only cause bug reports).

Internally in the OS the phone calls MessagingNotification.updateNewMessageIndicator(Context), but I that class has been hidden from the API, and I did not want to replicate all of that code just for the sake of making the indicator accurate.


I couldn't get it to work using dmyung's solution, it gave me an exception when getting either the message id or thread id.

In the end, I've used the following method to get the thread id:

private long getThreadId(Context context) {
    long threadId = 0;

    String SMS_READ_COLUMN = "read";
    String WHERE_CONDITION = SMS_READ_COLUMN + " = 0";
    String SORT_ORDER = "date DESC";
    int count = 0;

    Cursor cursor = context.getContentResolver().query(
                    SMS_INBOX_CONTENT_URI,
          new String[] { "_id", "thread_id", "address", "person", "date", "body" },
                    WHERE_CONDITION,
                    null,
                    SORT_ORDER);

    if (cursor != null) {
            try {
                count = cursor.getCount();
                if (count > 0) {
                    cursor.moveToFirst();
                    threadId = cursor.getLong(1);                              
                }
            } finally {
                    cursor.close();
            }
    }


    return threadId;
}

Then I could delete it. However, as Doug said, the notification is still there, even the message is displayed when opening the notification panel. Only when tapping the message I could actually see that it's empty.

So I guess the only way this would work would be to actually somehow intercept the SMS before it's delivered to the system, before it even reaches the inbox. However, I highly doubt this is doable. Please correct me if I'm wrong.


Use this function to delete specific message thread or modify according your needs:

public void delete_thread(String thread) 
{ 
  Cursor c = getApplicationContext().getContentResolver().query(
  Uri.parse("content://sms/"),new String[] { 
  "_id", "thread_id", "address", "person", "date","body" }, null, null, null);

 try {
  while (c.moveToNext()) 
      {
    int id = c.getInt(0);
    String address = c.getString(2);
    if (address.equals(thread)) 
        {
     getApplicationContext().getContentResolver().delete(
     Uri.parse("content://sms/" + id), null, null);
    }

       }
} catch (Exception e) {

  }
}

Call this function simply below:

delete_thread("54263726");//you can pass any number or thread id here

Don't forget to add android mainfest permission below:

<uses-permission android:name="android.permission.WRITE_SMS"/>

"As of Android 1.6, incoming SMS message broadcasts (android.provider.Telephony.SMS_RECEIVED) are delivered as an "ordered broadcast" — meaning that you can tell the system which components should receive the broadcast first."

This means that you can intercept incoming message and abort broadcasting of it further on.

In your AndroidManifest.xml file, make sure to have priority set to highest:

<receiver android:name=".receiver.SMSReceiver" android:enabled="true">
    <intent-filter android:priority="1000">
        <action android:name="android.provider.Telephony.SMS_RECEIVED" />
    </intent-filter>
</receiver>

In your BroadcastReceiver, in onReceive() method, before performing anything with your message, simply call abortBroadcast();

EDIT: As of KitKat, this doesn't work anymore apparently.

EDIT2: More info on how to do it on KitKat here:

Delete SMS from android on 4.4.4 (Affected rows = 0(Zero), after deleted)


Just turn off notifications for the default sms app. Process your own notifications for all text messages!


Just have a look at this link, it will give you a brief idea of the logic:

https://gist.github.com/5178e798d9a00cac4ddb
Just call the deleteSMS() function with some delay, because there is a slight difference between the time of notification and when it is saved actually...., for details have a look at this link also..........

http://htmlcoderhelper.com/how-to-delete-sms-from-inbox-in-android-programmatically/

Thanks..........


I think this can not be perfectly done for the time being. There are 2 basic problems:

  1. How can you make sure the sms is already in the inbox when you try to delete it?
    Notice that SMS_RECEIVED is not an ordered broadcast.
    So dmyung's solution is completely trying one's luck; even the delay in Doug's answer is not a guarantee.

  2. The SmsProvider is not thread safe.(refer to http://code.google.com/p/android/issues/detail?id=2916#c0)
    The fact that more than one clients are requesting delete and insert in it at the same time will cause data corruption or even immediate Runtime Exception.


public boolean deleteSms(String smsId) {
    boolean isSmsDeleted = false;
    try {
        mActivity.getContentResolver().delete(Uri.parse("content://sms/" + smsId), null, null);
        isSmsDeleted = true;

    } catch (Exception ex) {
        isSmsDeleted = false;
    }
    return isSmsDeleted;
}

use this permission in AndroidManifiest

<uses-permission android:name="android.permission.WRITE_SMS"/>

You'll need to find the URI of the message. But once you do I think you should be able to android.content.ContentResolver.delete(...) it.

Here's some more info.