One of the first things I did after I got my iPhone 3G was to setup my emails. In doing so, I soon came to realize one of the first shortcomings of this highly publicized device, which was the missing ability to mark all of my 792 messages as read. If you too rather spend your time differently than simply sitting there and going through hundreds of messages in order to mark them as read, here is a solution for you. However, let me first mention that this solution requires a jailbroken iPhone. Also let me say that if you know what you’re doing, all you have to do is to login to the SQLite database and then run the last two update commands at the end of this post.
Begin by installing SSH for your iPhone. If you don’t know how to do this, visit this tutorial on how to install SSH on your iPhone. Assuming you are now logged in as root on your iPhone, continue along with the instructions below.
Apple uses an SQLite database to keep track of your mailboxes, and their message counts and stats. Run the following command as root to login to this database:
sqlite3 /private/var/mobile/Library/Mail/Envelope\ Index
Once you’re in SQL console, list the tables buy simply running the following command:
.table
Out of the tables you see, you’re only concerned with messages and mailboxes. We start by examining the structure of the two tables. In SQLite, you can use the .schema followed by a table name to view the structure of a table. Below you can see what you should find when you run the .schema command.
sqlite> .schema mailboxes
CREATE TABLE mailboxes (ROWID INTEGER PRIMARY KEY,
url UNIQUE,
sequence_identifier TEXT,
total_count INTEGER DEFAULT 0,
unread_count INTEGER DEFAULT 0,
deleted_count INTEGER DEFAULT 0);
sqlite> .schema messages
CREATE TABLE messages (ROWID INTEGER PRIMARY KEY AUTOINCREMENT,
remote_id INTEGER, sender,
subject,
_to,
cc,
date_sent INTEGER,
date_received INTEGER,
sort_order INTEGER,
mailbox INTEGER,
remote_mailbox INTEGER,
original_mailbox INTEGER,
flags INTEGER,
read,
flagged,
deleted,
size INTEGER,
color,
encoding,
content_type);
CREATE INDEX date_index ON messages(date_received);
CREATE INDEX message_mailbox_index ON messages(mailbox, deleted, date_received DESC, sort_order DESC);
CREATE INDEX message_remote_mailbox_index ON messages(remote_mailbox, remote_id);
CREATE TRIGGER after_add_message AFTER INSERT ON messages
BEGIN
UPDATE mailboxes SET total_count = total_count + 1 WHERE mailboxes.ROWID = new.mailbox;
UPDATE mailboxes SET unread_count = unread_count + 1 WHERE mailboxes.ROWID = new.mailbox AND new.flags&1 = 0;
UPDATE mailboxes SET deleted_count = deleted_count + 1 WHERE mailboxes.ROWID = new.mailbox AND new.flags&2 > 0;
END;
CREATE TRIGGER after_delete_message AFTER DELETE ON messages
BEGIN
DELETE FROM threads WHERE threads.message_id == OLD.ROWID;
DELETE FROM message_data WHERE message_id = OLD.ROWID;
UPDATE mailboxes SET total_count = total_count - 1 WHERE mailboxes.ROWID = old.mailbox;
UPDATE mailboxes SET unread_count = unread_count - 1 WHERE mailboxes.ROWID = old.mailbox AND old.flags&1 = 0;
UPDATE mailboxes SET deleted_count = deleted_count - 1 WHERE mailboxes.ROWID = old.mailbox AND old.flags&2 > 0;
END;
CREATE TRIGGER after_update_message AFTER UPDATE ON messages
BEGIN
UPDATE mailboxes SET unread_count = unread_count - 1 WHERE mailboxes.ROWID = new.mailbox AND old.flags&1 = 0 AND new.flags&1 > 0;
UPDATE mailboxes SET unread_count = unread_count + 1 WHERE mailboxes.ROWID = new.mailbox AND old.flags&1 > 0 AND new.flags&1 = 0;
UPDATE mailboxes SET deleted_count = deleted_count - 1 WHERE mailboxes.ROWID = new.mailbox AND old.flags&2 > 0 AND new.flags&2 = 0;
UPDATE mailboxes SET deleted_count = deleted_count + 1 WHERE mailboxes.ROWID = new.mailbox AND old.flags&2 = 0 AND new.flags&2 > 0;
END;
From what gets printed, it should be easy to see how you can quickly mark all your messages as read. First notice that the triggers modify the mailboxes.unread_count. Therefore, what we ultimately want is that mailboxes.unread_count be zero. But there is a catch. Look at the where clause of the update statements and how the bitwise operation on messages.flags column is used to determine the mailboxes.unread_count. Thus if we simply run an update statement to set the mailboxes.unread_count, we’d only be there half way. This is because the next time any of the triggers are called, the mailboxes.unread_count would get updated incorrectly and thus leading numbers in negatives even.
To fix this, I sent an email to myself and looked at the messages.flags value before and after I read the message. Okay, so I do admit that I didn’t try to understand the full meaning of this column but I did notice that each time a message is marked as read, the flags is incremented by one unit. Based on this experience, I came up with these two commands below which so far have worked for me.
update messages set flags = flags + 1 where flags&1 = 0; update mailboxes set unread_count = 0;
After you run the above command, fully restart your iPhone (i.e. power off, and on). After reboot, run the mail. You should see all your messages as read, and the little red unread count bubble all gone. Enjoy!!
12 Comments until now
Works perfect. Did the job!!! Thanks Amir. It would be nice if someone can write a utility to do it automatically now
You don’t need to restart you phone completly. Just for a restart of the mail app.
1. go the mail application
2. push and hold the home button for 5 or 10 seconds. It will for the app to exit.
Worked a treat thanks
how to run those commands? Run it in MobileTerminal?
@nlhu yeah you could but it’s easier to ssh into your iphone and then you can copy and paste.
Tip works perfect but don’t forget to mention you need to install sqlite3 first, which can be done by “apt-get install sqlite3″
[...] It may not be easy but here is how I do it. How to mark all email messages as read on iPhone 3G : Missing Brace - http://www.missingbrace.com [...]
Back when I first jailbroke my iphone, there was an app to Mark All Read…I don’t know where to find it, or if it has been updated…but it is definitely possible to have an app that does this with a single touch.
I just wish I was smart enough to make it myself.
Thanks man it’s really been great. It works perfectly. You need to install first both apt-get and sqlite3 in order for the commands you’ve used to work.
Worked like a charm. You should update it to add the remarks regarding installing sqlite3 (it is available on cydia).
This is one useful tutorial…
thx a lot
This doesn’t appear to work for IMAP accounts because you would also need to set the messages on the server as read. After changing the values in the db and restarting Mail, the values are reset in the db because of the sync with the IMAP server
Thanks this saved me from opening 558 emails
1st Page Results Guaranteed
Do you wish you could increase your online leads?
Getting a GUARANTEED 1ST PAGE GOOGLE RANKING is easier and more cost-effective than you might think.
We have helped a lot of businesses thrive in this market and we can help you! Simply hit reply and I’ll share with you the cost and the benefits See you at the top!