在之前的一篇博客中介绍了邮件接收POP3,今天就来学习下另外一种协议IMAP,android里面还有一中邮件接收协议Exchange,这个还没有具体的学习,以后学习了再记录下来。
IMAP协议(Internet Mail Access Protocol,Internet邮件访问协议),也是一种获取邮件的协议,它也POP3协议的主要是用户可以不用把所有的邮件全部都下载,可以直接通过客户端对邮件服务器去访问。IMAP协议是运行在TCP/IP协议之上,端口号是143,POP3协议的端口号是110。
同样也可以在电脑的通过cmd 用imap协议登录邮箱
输入cmd之后在命令行端输入telnet imap.qq.com 143 ,如果是其他邮箱,不如163,sina 对应的应该输入 imap.163.com ,imap.sina.com,输入连接成功后会出现下面的界面
这里说一下哦,如果输入telnet imap.qq.com 143时出现telnet不是内部命令这是因为你的电脑上的telnet客户端的设置没有打开,可以在控制面板—程序和功能—-打开和关闭window的功能,这里面把telnet客户端勾选上就可以了。
连接成功之后可以输入你的账户名和密码啦
登录的命令就是A01 login 账户名称 密码 (注意账户名和密码中间有空格)
可以通过A02 LIST “” *命令列出信箱列表,注意哦 imap协议获取的邮件信箱列表,相比pop3会多出垃圾箱。
A03 Select INBOX 是选择收件箱
A06 Fetch 1 full 这是获取第一封邮件的邮件头
A07 Fetch 1 rfc822 获取第一封邮件的完整内容
imap的命令相比pop3的命令要多,这里就不一一列举了拉
在这里呢学习下在android源码Email模块对imap协议接收邮件的实现
在PopImapSyncAdapterService.java 这个类是imap和pop3 sync邮件的关键类
private static class SyncAdapterImpl extends AbstractThreadedSyncAdapter {
public SyncAdapterImpl(Context context) {
super(context, true /* autoInitialize */);
}
//在onPerformSync方法里面去同步邮件
@Override
public void onPerformSync(android.accounts.Account account, Bundle extras,
String authority, ContentProviderClient provider, SyncResult syncResult) {
PopImapSyncAdapterService.performSync(getContext(), account, extras, provider,
syncResult);
}
}
AbstractThreadedSyncAdapter 是android提供的一个同步账户的类,它是一个抽象类,里面的onPerformSync()是需要重写的,当AbstractThreadedSyncAdapter 收到开始同步startSync()的请求后会去调用onPerformSync()
所以把我们的请求操作都封装到onPerformSync()中,同时为了让系统可以找到我们要同步的账户,需要在这个Service 里面配置action android:name=”android.content.SyncAdapter” 和metadata
private static void performSync(){
.....
在这里有调用到sync()
for (long mailboxId: mailboxesToUpdate) {
sync(context, mailboxId, extras, syncResult, false, 0);
.....
}
}
private static void sync(){
.....
在这里通过判断用户选择的接收协议是imap和pop3 分别进行同步邮件的操作
if (protocol.equals(legacyImapProtocol)) {
status = ImapService.synchronizeMailboxSynchronous(context, account,
mailbox, deltaMessageCount != 0, uiRefresh);
} else {
status = Pop3Service.synchronizeMailboxSynchronous(context, account,
mailbox, deltaMessageCount);
}
EmailServiceStatus.syncMailboxStatus(resolver, extras, mailboxId, status, 0,
lastSyncResult);
.......
}
现在看下使用imap协议同步邮件,pop3邮件同步邮件协议在之前的一篇里面已经简单介绍啦
public static synchronized int synchronizeMailboxSynchronous(Context context,
final Account account, final Mailbox folder, final boolean loadMore,
final boolean uiRefresh) throws MessagingException {
Store remoteStore = null;
remoteStore = Store.getInstance(account, context);
processPendingActionsSynchronous(context, account, remoteStore, uiRefresh);
这里就是用imap协议sync邮件
synchronizeMailboxGeneric(context, account, remoteStore, folder, loadMore, uiRefresh);
nc.cancelLoginFailedNotification(account.mId);
}
private synchronized static void synchronizeMailboxGeneric(){
localOldestCursor = resolver.query(EmailContent.Message.CONTENT_URI,)..
final Folder remoteFolder = remoteStore.getFolder(mailbox.mServerId);
final int remoteMessageCount = remoteFolder.getMessageCount();
Message[] remoteMessages;
remoteMessages = remoteFolder.getMessages(0, endDate, null);
//进行本地uid索引
Cursor localUidCursor = null;
HashMap<String, LocalMessageInfo> localMessageMap = new HashMap<String, LocalMessageInfo>();
try {
final long queryEndDate = 0;
localUidCursor = resolver.query(
EmailContent.Message.CONTENT_URI,
LocalMessageInfo.PROJECTION,
EmailContent.MessageColumns.ACCOUNT_KEY + "=?"
+ " AND " + MessageColumns.MAILBOX_KEY + "=?"
+ " AND " + MessageColumns.TIMESTAMP + ">=?",
new String[] {
String.valueOf(account.mId),
String.valueOf(mailbox.mId),
String.valueOf(queryEndDate) },
null);
while (localUidCursor.moveToNext()) {
LocalMessageInfo info = new LocalMessageInfo(localUidCursor);
if (!TextUtils.isEmpty(info.mServerId)) {
localMessageMap.put(info.mServerId, info);
}
}
} finally {
if (localUidCursor != null) {
localUidCursor.close();
}
}
}
final ArrayList<Message> unsyncedMessages = new ArrayList<Message>();
final HashMap<String, Message> remoteUidMap = new HashMap<String, Message>();
//这里是与服务器上面的邮件对比,如果本地没有,加入到unsyncedMessages中,最后将unsyncedMessages 去download下来
for (int i = remoteMessages.length - 1; i >= 0; i--) {
Message message = remoteMessages[i];
remoteUidMap.put(message.getUid(), message);
LocalMessageInfo localMessage = localMessageMap.get(message.getUid());
if (localMessage == null ||
(localMessage.mFlagLoaded == EmailContent.Message.FLAG_LOADED_UNLOADED) ||
(localMessage.mFlagLoaded == EmailContent.Message.FLAG_LOADED_PARTIAL)) {
unsyncedMessages.add(message);
}
if (unsyncedMessages.size() > 0) {
//download邮件
downloadFlagAndEnvelope(context, account, mailbox, remoteFolder, unsyncedMessages,
localMessageMap, unseenMessages);
}
对imap协议同步邮件的流程只是知道个大概的流程,没有POP3的流程来的印象深刻,还是因为之前的一个POP3 协议同步邮件bug让我一个从来的没有看过邮件代码的小菜鸟慢慢的通过log分析才接触邮件代码。
记得当时连邮件的接收和发送协议都不知道是啥,硬着头皮去通过log看代码,虽然到最后用个很搓的办法给规避了。不过这个问题也是让我一直记忆深刻。对邮件的学习还只是懂一点皮毛,或者说是一点皮毛都算不上。不过还是希望通过今后的学习,让自己学到的东西更过啦。