Monthly Archives: January 2012

使用JavaMail API

使用JavaMail API,接上文javax.mail.internet api 学习
1.发送邮件
在获得了Session后,建立并填入邮件信息,然后发送它到邮件服务器。这便是使用Java Mail API发送邮件的过程,在发送邮件之前,我们需要设置SMTP服务器:通过设置Properties的mail.smtp.host属性。

String host = …;
String from = …;
String to = …;
// Get system properties
Properties props = System.getProperties();
// Setup mail server
props.put(“mail.smtp.host”, host);
// Get session
Session session = Session.getDefaultInstance(props, null);// Define message
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));message.addRecipient(Message.RecipientType.TO,   new InternetAddress(to));message.setSubject(“Hello JavaMail”);
message.setText(“Welcome to JavaMail”);
// Send message
Transport.send(message);

由于建立邮件信息和发送邮件的过程中可能会抛出异常,所以我们需要将上面的代码放入到try-catch结构块中。
2.接收邮件
为了在读取邮件,我们获得了session,并且连接到了邮箱的相应store,打开相应的Folder,然后得到我们想要的邮件,当然别忘记了在结束时关闭连接。

String host = …;
String username = …;
String password = …;
// Create empty properties
Properties props = new Properties();
// Get session
Session session = Session.getDefaultInstance(props, null);
// Get the store
Store store = session.getStore(“pop3″);
store.connect(host, username, password);
// Get folder
Folder folder = store.getFolder(“INBOX”);
folder.open(Folder.READ_ONLY);
// Get directory
Message message[] = folder.getMessages();
for (int i=0, n=message.length; i++)…

上面的代码所作的是从邮箱中读取每个邮件,并且显示邮件的发信人地址和主题。从技术角度讲,这里存在着一个异常的可能:当发信人地址为空时,getFrom()[0]将抛出异常。

下 面的代码片断有效的说明了如何读取邮件内容,在显示每个邮件发信人和主题后,将出现用户提示从而得到用户是否读取该邮件的确认,如果输入YES的话,我们 可用Message.writeTo(java.io.OutputStream os)方法将邮件内容输出到控制台上,关于 Message.writeTo()的具体用法请看JavaMail API。

BufferedReader reader = new BufferedReader (  new InputStreamReader(System.in));
// Get directory
Message message[] = folder.getMessages();
for (int i=0, n=message.length; i…

3.删除邮件和标志
设置与message相关的Flags是删除邮件的常用方法。这些Flags表示了一些系统定义和用户定义的不同状态。在Flags类的内部类Flag中预定义了一些标志:

Flags.Flag.ANSWERED
Flags.Flag.DELETED
Flags.Flag.DRAFT
Flags.Flag.FLAGGED
Flags.Flag.RECENT
Flags.Flag.SEEN
Flags.Flag.USER

但 需要在使用时注意的:标志存在并非意味着这个标志被所有的邮件服务器所支持。例如,对于删除邮件的操作,POP协议不支持上面的任何一个。所以要确定哪些 标志是被支持的??通过访问一个已经打开的Folder对象的getPermanetFlags()方法,它将返回当前被支持的Flags类对象。
删除邮件时,我们可以设置邮件的DELETED标志:

message.setFlag(Flags.Flag.DELETED, true);

但是首先要采用READ_WRITE的方式打开Folder:

folder.open(Folder.READ_WRITE);

在对邮件进行删除操作后关闭Folder时,需要传递一个true作为对删除邮件的擦除确认。

folder.close(true);

Folder类中另一种用于删除邮件的方法expunge()也同样可删除邮件,但是它并不为sun提供的POP3实现支持,而其它第三方提供的POP3实现支持或者并不支持这种方法。
另外,介绍一种检查某个标志是否被设置的方法:Message.isSet(Flags.Flag flag)方法,其中参数为被检查的标志。

4.邮件认证
我 们在前面已经学会了如何使用Authenticator类来代替直接使用用户名和密码这两字符串作为 Session.getDefaultInstance()或者Session.getInstance()方法的参数。在前面的小试牛刀后,现在我们将 了解到全面认识一下邮件认证。
我们在此取代了直接使用邮件服务器主机名、用户名、密码这三个字符串作为连接到POP3 Store的方式,使用存储了邮件服务器主机名信息的属性文件,并在获得Session时传入自定义的Authenticator实例:

// Setup properties
Properties props = System.getProperties();
props.put(“mail.pop3.host”, host);
// Setup authentication, get session
Authenticator auth = new PopupAuthenticator();
Session session = Session.getDefaultInstance(props, auth);
// Get the store
Store store = session.getStore(“pop3″);
store.connect();

PopupAuthenticator 类继承了抽象类Authenticator,并且通过重载Authenticator类的getPasswordAuthentication()方法返 回PasswordAuthentication类对象。而getPasswordAuthentication()方法的参数param是以逗号分割的 用户名、密码组成的字符串。

import javax.mail.*;
import java.util.*;

public class PopupAuthenticator extends Authenticator {
public PasswordAuthentication getPasswordAuthentication(String param) {
String username, password;
StringTokenizer st = new StringTokenizer(param, ”,”);
username = st.nextToken();
password = st.nextToken();
return new PasswordAuthentication(username, password);
}
}

5.回复邮件
回复邮件的方法很简单:使用Message类的reply()方法,通过配 置回复邮件的收件人地址和主题(如果没有提供主题的话,系统将默认将“Re:”作为邮件的主体),这里不需要设置任何的邮件内容,只要复制发信人或者 reply-to到新的收件人。而reply()方法中的boolean参数表示是否将邮件回复给发送者(参数值为false),或是恢复给所有人(参数 值为true)。
补充一下,reply-to地址需要在发信时使用setReplyTo()方法设置。

MimeMessage reply = (MimeMessage)message.reply(false);
reply.setFrom(new InternetAddress(“president@whitehouse.gov”));
reply.setText(“Thanks”);
Transport.send(reply);

6.转发邮件
转发邮件的过程不如前面的回复邮件那样简单,它将建立一个转发邮件,这并非一个方法就能做到。
每 个邮件是由多个部分组成,每个部分称为一个邮件体部分,是一个BodyPart类对象,对于MIME类型邮件来讲就是MimeBodyPart类对象。这 些邮件体包含在成为Multipart的容器中对于MIME类型邮件来讲就是MimeMultiPart类对象。在转发邮件时,我们建立一个文字邮件体部 分和一个被转发的文字邮件体部分,然后将这两个邮件体放到一个Multipart中。说明一下,复制一个邮件内容到另一个邮件的方法是仅复制它的 DataHandler(数据处理者)即可。这是由JavaBeans Activation Framework定义的一个类,它提供了对邮件内容的操 作命令的访问、管理了邮件内容操作,是不同的数据源和数据格式之间的一致性接口。

// Create the message to forward
Message forward = new MimeMessage(session);
// Fill in header
forward.setSubject(“Fwd: ” + message.getSubject());
forward.setFrom(new InternetAddress(from));
forward.addRecipient(Message.RecipientType.TO,   new InternetAddress(to));
// Create your new message part
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setText(  ”Here you go with the original message:\n\n”);
// Create a multi-part to combine the parts
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
// Create and fill part for the forwarded content
messageBodyPart = new MimeBodyPart();
messageBodyPart.setDataHandler(message.getDataHandler());
// Add part to multi part
multipart.addBodyPart(messageBodyPart);
// Associate multi-part with message
forward.setContent(multipart);
// Send message
Transport.send(forward);

7.使用附件
附件作为与邮件相关的资源经常以文本、表格、图片等格式出现,如流行的邮件客户端一样,我们可以用JavaMail API从邮件中获取附件或是发送带有附件的邮件。

A.发送带有附件的邮件
发送带有附件的邮件的过程有些类似转发邮件,我们需要建立一个完整邮件的各个邮件体部分,在第一个部分(即我们的邮件内容文字)后,增加一个具有DataHandler的附件而不是在转发邮件时那样复制第一个部分的DataHandler。

如果我们将文件作为附件发送,那么要建立FileDataSource类型的对象作为附件数据源;如果从URL读取数据作为附件发送,那么将要建立URLDataSource类型的对象作为附件数据源。

然后将这个数据源(FileDataSource或是URLDataSource)对象作为DataHandler类构造方法的参数传入,从而建立一个DataHandler对象作为数据源的DataHandler。

接着将这个DataHandler设置为邮件体部分的DataHandler。这样就完成了邮件体与附件之间的关联工作,下面的工作就是BodyPart的setFileName()方法设置附件名为原文件名。

最后将两个邮件体放入到Multipart中,设置邮件内容为这个容器Multipart,发送邮件。

// Define message
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.addRecipient(Message.RecipientType.TO,   new InternetAddress(to));
message.setSubject(“Hello JavaMail Attachment”);
// Create the message part
BodyPart messageBodyPart = new MimeBodyPart();
// Fill the message
messageBodyPart.setText(“Pardon Ideas”);
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
// Part two is attachment
messageBodyPart = new MimeBodyPart();
DataSource source = new FileDataSource(filename);
messageBodyPart.setDataHandler(new DataHandler(source));
messageBodyPart.setFileName(filename);
multipart.addBodyPart(messageBodyPart);
// Put parts in message
message.setContent(multipart);
// Send the message
Transport.send(message);

如果我们使用servlet实现发送带有附件的邮件,则必须上传附件给servlet,这时需要注意提交页面form中对编码类型的设置应为multipart/form-data。

B.读取邮件中的附件
读取邮件中的附件的过程要比发送它的过程复杂一点。因为带有附件的邮件是多部分组成的,我们必须处理每一个部分获得邮件的内容和附件。
但 是如何辨别邮件信息内容和附件呢?Sun在Part类(BodyPart类实现的接口类)中提供了getDisposition()方法让开发者获得邮件 体部分的部署类型,当该部分是附件时,其返回之将是Part.ATTACHMENT。但附件也可以没有部署类型的方式存在或者部署类型为 Part.INLINE,无论部署类型为Part.ATTACHMENT还是Part.INLINE,我们都能把该邮件体部分导出保存。

Multipart mp = (Multipart)message.getContent();
for (int i=0, n=multipart.getCount(); i…

下列代码中使用了saveFile方法是自定义的方法,它根据附件的文件名建立一个文件,如果本地磁盘上存在名为附件的文件,那么将在文件名后增加数字表示区别。然后从邮件体中读取数据写入到本地文件中(代码省略)。

// from saveFile()
File file = new File(filename);
for (int i=0; file.exists(); i++)
{
file = new File(filename+i);
}

以上是邮件体部分被正确设置的简单例子,如果邮件体部分的部署类型为null,那么我们通过获得邮件体部分的MIME类型来判断其类型作相应的处理,代码结构框架如下:

if (disposition == null) {
// Check if plain
MimeBodyPart mbp = (MimeBodyPart)part;
if (mbp.isMimeType(“text/plain”)) {
// Handle plain
} else {
// Special non-attachment cases here of
// image/gif, text/html, .
..
}

}

8.处理HTML邮件
前面的例子中发送的邮件都是以文本为内容的(除了附件),下面将介绍如何接收和发送基于HTML的邮件。
A.发送HTML邮件
假如我们需要发送一个HTML文件作为邮件内容,并使邮件客户端在读取邮件时获取相关的图片或者文字的话,只要设置邮件内容为html代码,并设置内容类型为text/html即可:

String htmlText = ”<h1>Hello</h1>” ;
message.setContent(htmlText, ”text/html”));

请注意:这里的图片并不是在邮件中内嵌的,而是在URL中定义的。邮件接收者只有在线时才能看到。
在接收邮件时,如果我们使用JavaMail API接收邮件的话是无法实现以HTML方式显示邮件内容的。因为JavaMail API邮件内容视为二进制流。所以要显示HTML内容的邮件,我们必须使用JEditorPane或者第三方HTML展现组件。

以下代码显示了如何使用JEditorPane显示邮件内容:

if (message.getContentType().equals(“text/html”)) {
String content = (String)message.getContent();
JFrame frame = new JFrame();
JEditorPane text = new JEditorPane(“text/html”, content);
text.setEditable(false);
JScrollPane pane = new JScrollPane(text);
frame.getContentPane().add(pane);
frame.setSize(300, 300);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.show();
}

B.在邮件中包含图片
如 果我们在邮件中使用HTML作为内容,那么最好将HTML中使用的图片作为邮件的一部分,这样无论是否在线都会正确的显示HTML中的图片。处理方法就是 将HTML中用到的图片作为邮件附件并使用特殊的cid URL作为图片的引用,这个cid就是对图片附件的Content-ID头的引用。
处理内嵌图片就像向邮件中添加附件一样,不同之处在于我们必须通过设置图片附件所在的邮件体部分的header中Content-ID为一个随机字符串,并在HTML中img的src标记中设置为该字符串。这样就完成了图片附件与HTML的关联。

String file = …;
// Create the messageMessage message = new MimeMessage(session);// Fill its headers
message.setSubject(“Embedded Image”);
message.setFrom(new InternetAddress(from));
message.addRecipient(Message.RecipientType.TO,   new InternetAddress(to));
// Create your new message part
BodyPart messageBodyPart = new MimeBodyPart();String htmlText = ”"<h1>Hello</h1>” ;
messageBodyPart.setContent(htmlText, ”text/html”);
// Create a related multi-part to combine the parts
MimeMultipart multipart = new MimeMultipart(“related”);
multipart.addBodyPart(messageBodyPart);
// Create part for the image
messageBodyPart = new MimeBodyPart();
// Fetch the image and associate to part
DataSource fds = new FileDataSource(file);
messageBodyPart.setDataHandler(new DataHandler(fds));
messageBodyPart.setHeader(“Content-ID”,”");
// Add part to multi-part
multipart.addBodyPart(messageBodyPart);
// Associate multi-part with message
message.setContent(multipart);

9.在邮件中搜索短语
JavaMail API提供了过滤器机制,它被用来建立搜索短语。这个短语由javax.mail.search包中的SearchTerm抽象类来定义,在定义后我们便可以使用Folder的Search()方法在Folder中查找邮件:
SearchTerm st = …;Message[] msgs = folder.search(st);
下面有22个不同的类(继承了SearchTerm类)供我们使用:
AND terms (class AndTerm)
OR terms (class OrTerm)
NOT terms (class NotTerm)
SENT DATE terms (class SentDateTerm)
CONTENT terms (class BodyTerm)
HEADER terms (FromTerm / FromStringTerm, RecipientTerm / RecipientStringTerm, SubjectTerm, etc.)
使用这些类定义的断语集合,我们可以构造一个逻辑表达式,并在Folder中进行搜索。下面是一个实例:在Folder中搜索邮件主题含有“ADV”字符串或者发信人地址为friend@public.com的邮件。

SearchTerm st = new OrTerm(new SubjectTerm(“ADV:”), new FromStringTerm(“friend@public.com”));
Message[] msgs = folder.search(st);

 

javax.mail.internet API 学习

前些天编程,用了个这样的数据传输方式,在http POST消息中传MIME数据包。于是找到javax.mail.internet的包用。在Java EE 1.5的库里包含这个包。现在有的MIME包不仅仅这一个,还有很多,更有千秋。比如这个包的Countent-Type 的 boundary字段是自动生成的,还不太方便取出来。有些包是能够自己设置boundary字段。

下面转载了这个包的基本使用方法,供学习参考。MIME学习请参考这里

++++++++++++++++++++++++++++++++++++++++++++

打开JavaMail.jar文件,我们将发现在javax.mail的包下面存在着一些核心类:Session、Message、Address、Authenticator、Transport、Store、Folder。而且在 javax.mail.internet包中还有一些常用的子类。

 

A.Session

Session类定义了基本的邮件会话。就像Http会话那样,我们进行收发邮件的工作都是基于这个会话的。Session对象利用了java.util.Properties对象获得了邮件服务器、用户名、密码信息和整个应用程序都要使用到的共享信息。

Session类的构造方法是私有的,所以我们可以使用Session类提供的getDefaultInstance()这个静态工厂方法获得一个默认的Session对象:

1 Properties props = new Properties();// fill props with any information
2  Session session = Session.getDefaultInstance(props, null);

或者使用getInstance()这个静态工厂方法获得自定义的Session:

1 Properties props = new Properties();// fill props with any information
2  Session session = Session.getInstance(props, null);

从上面的两个例子中不难发现,getDefaultInstance()和getInstance()方法的第二个参数都是null,这是因为在上面的例子中并没有使用到邮件授权,下文中将对授权进行详细介绍。
从很多的实例看,在对mail server进行访问的过程中使用共享的Session是足够的,即使是工作在多个用户邮箱的模式下也不例外。

B.Message

当我们建立了Session对象后,便可以构造被 发送的信息体了。在这里SUN提供了Message类型来帮助开发者完成这项工作。由于Message是一个抽象类,大多数情况下,我们使用 javax.mail.internet.MimeMessage这个子类,该类是使用MIME类型、MIME信息头的邮箱信息。信息头只能使用US- ASCII字符,而非ASCII字符将通过编码转换为ASCII的方式使用。

为了建立一个MimeMessage对象,我们必须将Session对象作为MimeMessage构造方法的参数传入:

1 MimeMessage message = new MimeMessage(session);

注意:对于MimeMessage类来讲存在着多种构造方法,比如使用输入流作为参数的构造方法。

在建立了MimeMessage对象后,我们需要设置它的各个part,对于MimeMessage类来说,这些part就是MimePart接口。最基本的设置信息内容的方法就是通过表示信息内容和米么类型的参数调用setContent()方法:

1 message.setContent(“Hello”, “text/plain”);

然而,如果我们所使用的MimeMessage中信息内容是文本的话,我们便可以直接使用setText()方法来方便的设置文本内容:

1 message.setText(“Hello”);

前面所讲的两种方法,对于文本信息,后者更为合适。而对于其它的一些信息类型,比如HTML信息,则要使用前者。
别忘记了,使用setSubject()方法对邮件设置邮件主题:

1 message.setSubject(“First”);

C.Address

到这里,我们已经建立了Session和Message,下面将介绍如何使用邮件地址类:Address。像Message一样,Address类也是一个抽象类,所以我们将使用javax.mail.internet.InternetAddress这个子类。

通过传入代表邮件地址的字符串,我们可以建立一个邮件地址类:

1 Address address = new InternetAddress(“president@whitehouse.gov”);

如果要在邮件地址后面增加名字的话,可以通过传递两个参数:代表邮件地址和名字的字符串来建立一个具有邮件地址和名字的邮件地址类:

1 Address address = new InternetAddress(“president@whitehouse.gov”, “George Bush”);

本文在这里所讲的邮件地址类是为了设置邮件信息的发信人和收信人而准备的,在建立了邮件地址类后,我们通过message的setFrom()和setReplyTo()两种方法设置邮件的发信人:

1 message.setFrom(address);message.setReplyTo(address);

若在邮件中存在多个发信人地址,我们可用addForm()方法增加发信人:

1 Address address[] = …;
2 message.addFrom(address);

为了设置收信人,我们使用addRecipient()方法增加收信人,此方法需要使用Message.RecipientType的常量来区分收信人的类型:

1 message.addRecipient(type, address)

下面是Message.RecipientType的三个常量:

1 Message.RecipientType.TO
2 Message.RecipientType.CC
3 Message.RecipientType.BCC

因此,如果我们要发送邮件给总统,并发用一个副本给第一夫人的话,下面的方法将被用到:

1 Address toAddress = new InternetAddress(“vice.president@whitehouse.gov”);
2 Address ccAddress = new InternetAddress(“first.lady@whitehouse.gov”);
3 message.addRecipient(Message.RecipientType.TO, toAddress);
4 message.addRecipient(Message.RecipientType.CC, ccAddress);

JavaMail API并没有提供检查邮件地址有效性的机制。当然我们可以自己完成这个功能:验证邮件地址的字符是否按照RFC822规定的格式书写或者通过DNS服务器上的MX记录验证等。

D.Authenticator

像java.net类那样,JavaMail API通过使用授权者类 (Authenticator)以用户名、密码的方式访问那些受到保护的资源,在这里“资源”就是指邮件服务器。在javax.mail包中可以找到这个 JavaMail的授权者类(Authenticator)。

在使用Authenticator这个抽象类时,我们必须采用继承该抽象类的方式,并且该继 承类必须具有返回PasswordAuthentication对象(用于存储认证时要用到的用户名、密 码)getPasswordAuthentication()方法。并且要在Session中进行注册,使Session能够了解在认证时该使用哪个类。

下面代码片断中的MyAuthenticator就是一个Authenticator的子类:

1 Properties props = new Properties();// fill props with any information
2  Authenticator auth = new MyAuthenticator();
3 Session session = Session.getDefaultInstance(props, auth);

E.Transport

在发送信息时,Transport类将被用到。这个类实现了发送信息的协议(通称为SMTP),此类是一个抽象类,我们可以使用这个类的静态方法send()来发送消息:

1 Transport.send(message);

当然,方法是多样的。我们也可由Session获得相应协议对应的Transport实例。并通过传递用户名、密码、邮件服务器主机名等参数建立与邮件服务器的连接,并使用sendMessage()方法将信息发送,最后关闭连接:

1 message.saveChanges(); // implicit with send()
2  Transport transport = session.getTransport(“smtp”);
3 transport.connect(host, username, password);
4 transport.sendMessage(message, message.getAllRecipients());
5 transport.close();

评论:上面的方法是一个很好的方法,尤其是在我们在同一个邮件服务器上发送多个邮件时。因为 这时我们将在连接邮件服务器后连续发送邮件,然后再关闭掉连接。send()这个基本的方法是在每次调用时进行与邮件服务器的连接的,对于在同一个邮件服 务器上发送多个邮件来讲可谓低效的方式。

注意:如果需要在发送邮件过程中监控mail命令的话,可以在发送前设置debug标志:

1 session.setDebug(true);

F.Store和Folder

接 收邮件和发送邮件很类似都要用到Session。但是在获得Session后,我们需要从Session中获取特定类型的Store,然后连接到 Store,这里的Store代表了存储邮件的邮件服务器。在连接Store的过程中,极有可能需要用到用户名、密码或者Authenticator。

1 Store store = session.getStore(“pop3″);
2 store.connect(host, username, password);

在连接到Store后,一个Folder对象即目录对象将通过Store的getFolder()方法被返回,我们可从这个Folder中读取邮件信息:

1 Folder folder = store.getFolder(“INBOX”);
2 folder.open(Folder.READ_ONLY);
3 Message message[] = folder.getMessages();

上面的例子首先从Store中获得INBOX这个Folder(对于POP3协议只有一个名为INBOX的Folder有效),然后以只读(Folder.READ_ONLY)的方式打开Folder,最后调用Folder的 getMessages()方法得到目录中所有Message的数组。

注意:对于POP3协议只 有一个名为INBOX的Folder有效,而对于IMAP协议,我们可以访问多个Folder(想想前面讲的IMAP协议)。而且SUN在设计 Folder的getMessages()方法时采取了很智能的方式:首先接收新邮件列表,然后再需要的时候(比如读取邮件内容)才从邮件服务器读取邮件 内容。

在读取邮件时,我们可以用Message类的getContent()方法接收邮件或是writeTo()方法将邮件保存,getContent()方法只接收邮件内容(不包含邮件头),而writeTo()方法将包括邮件头。

1 System.out.println(((MimeMessage)message).getContent());

在读取邮件内容后,别忘记了关闭Folder和Store。

1 folder.close(aBoolean);
2 store.close();

传递给Folder.close()方法的boolean类型参数表示是否在删除操作邮件后更新Folder。

转自:http://tech.ccidnet.com/art/3741/20060531/567247_1.html

MIME详细介绍

(注:本文转自CSDN,因本人学习,只是做一笔记,以防遗忘。)

Q 什么是MIME?什么是MIME邮件?

A MIME, 全称为“Multipurpose Internet Mail Extensions”, 比较确切的中文名称为“多用途互联网邮件扩展”。它是当前广泛应用的一种电子邮件技术规范,基本内容定义于RFC 2045-2049。

自然,MIME邮件就是符合MIME规范的电子邮件,或者说根据MIME规范编码而成的电子邮件。

在MIME出台之前,使用RFC 822只能发送基本的ASCII码文本信息,邮件内容如果要包括二进制文件、声音和动画等,实现起来非常困难。MIME提供了一种可以在邮件中附加多种不 同编码文件的方法,弥补了原来的信息格式的不足。实际上不仅仅是邮件编码,现在MIME经成为HTTP协议标准的一个部分。

下面举几个MIME邮件的例子,让我们先对MIME编码的格式有个直观的印象。例1是最简单的,只带纯文本正 文,基本上就是RFC 822格式;例2复杂一些,包含纯文本和超文本正文;例3是最复杂的,包含纯文本正文、超文本正文、内嵌资源和文件附件。其中,行号和行号后的空格是为了 分析方便而另外加的,“… … … …”表示此处省略了大段编码。

例1

1 Date: Thu, 18 Apr 2002 09:32:45 +0800
2 From: <bhw98@sina.com>
3 To: <bhwang@jlonline.com>
4 Subject: Test
5 Mime-Version: 1.0
6 Content-Type: text/plain; charset=”iso-8859-1″
7
8 This is a simple mail.
9

例2

1 From: “bhw98″ <bhw98@sina.com>
2 Reply-To: bhw98@sina.com
3 To: <bluesky7810@163.com>
4 Subject: Re: help
5 X-Mailer: Foxmail 4.2 [cn]
6 Mime-Version: 1.0
7 Content-Type: multipart/alternative;
8 boundary=”=====002_Dragon307572345230_=====”
9
10
11 This is a multi-part message in MIME format.
12
13 –=====002_Dragon307572345230_=====
14 Content-Type: text/plain; charset=”GB2312″
15 Content-Transfer-Encoding: quoted-printable
16
17 bluesky7810=A3=AC=C4=FA=BA=C3=A3=A1
18
19 =A1=A1=A1=A1=D4=DA=CF=C2=C6=AA=D7=EE=BA=F3=BF=C9=D2=D4=CF=C2=D4=D8=B0=A1=A3=AC=C4=E3
… … … …
30 =A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A12003-04-07
31
32 –=====002_Dragon307572345230_=====
33 Content-Type: text/html; charset=”GB2312″
34 Content-Transfer-Encoding: quoted-printable
35
36 <!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.0 Transitional//EN”>
37 <HTML><HEAD>
38 <META content=3D”text/html; charset=3Dgb2312″=
39 http-equiv=3DContent-Type>
40 <META content=3D”MSHTML 5.00.2920.0″ name=3DGENERATOR>
… … … …
79 </HTML>
80
81 –=====002_Dragon307572345230_=====–
82

例3

1 Return-Path: <bluesky7810@163.com>
2 Delivered-To: bhw98@sina.com
3 Received: (qmail 75513 invoked by alias); 20 May 2002 02:19:53 -0000
4 Received: from unknown (HELO bluesky) (61.155.118.135)
5 by 202.106.187.143 with SMTP; 20 May 2002 02:19:53 -0000
6 Message-ID: <007f01c3111c$742fec00$0100007f@bluesky>
7 From: “=?gb2312?B?wLbAtrXEzOwNCg==?=” <bluesky7810@163.com>
8 To: “bhw98″ <bhw98@sina.com>
9 Cc: <bhwang@jlonline.com>
10 Subject: =?gb2312?B?ztK1xLbgtK6/2rPM0PI=?=
11 Date: Sat, 20 May 2002 10:03:36 +0800
12 MIME-Version: 1.0
13 Content-Type: multipart/mixed;
14 boundary=”—-=_NextPart_000_007A_01C3115F.80DFC5E0″
15 X-Priority: 3
16 X-MSMail-Priority: Normal
17 X-Mailer: Microsoft Outlook Express 5.00.2919.6700
18 X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2919.6700
19
20 This is a multi-part message in MIME format.
21
22 ——=_NextPart_000_007A_01C3115F.80DFC5E0
23 Content-Type: multipart/related; type=”multipart/alternative”;
24 boundary=”—-=_NextPart_001_007B_01C3115F.80DFC5E0″
25
26
27 ——=_NextPart_001_007B_01C3115F.80DFC5E0
28 Content-Type: multipart/alternative;
29 boundary=”—-=_NextPart_002_007C_01C3115F.80DFC5E0″
30
31 ——=_NextPart_002_007C_01C3115F.80DFC5E0
32 Content-Type: text/plain; charset=”gb2312″
33 Content-Transfer-Encoding: quoted-printable
34
35 bhw98, =C4=E3=BA=C3!
36 =D5=E2=CA=C7=CE=D2=D0=B4=B5=C4=B6=E0=B4=AE=BF=DA=CD=A8=D0=C5=B5=C4=B3=CC=D0=
37 =F2, =C7=EB=D6=B8=BD=CC!
38
39
40 ——=_NextPart_002_007C_01C3115F.80DFC5E0
41 Content-Type: text/html; charset=”gb2312″
42 Content-Transfer-Encoding: quoted-printable
43
44 <!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.0 Transitional//EN”>
45 <HTML><HEAD><TITLE>=C7=E7=C0=CA</TITLE>
46 <META content=3D”text/html; charset=3Dgb2312″ http-equiv=3DContent-Type>
47 <STYLE>BODY {
48 COLOR: #0033cc; FONT-FAMILY: =CB=CE=CC=E5, Arial, Helvetica; FONT-SIZE: =
49 9pt; MARGIN-LEFT: 10px; MARGIN-TOP: 25px
50 }
51 </STYLE>
52 <META content=3D”MSHTML 5.00.2920.0″ name=3DGENERATOR></HEAD>
53 <BODY background=3Dcid:007901c3111c$72b978a0$0100007f@bluesky =
54 bgColor=3D#ffffff>
55 <DIV>
56 <DIV>bhw98, =C4=E3=BA=C3!</DIV>
57 <P>=D5=E2=CA=C7=CE=D2=D0=B4=B5=C4=B6=E0=B4=AE=BF=DA=CD=A8=D0=C5=B5=C4=B3=CC=
58 =D0=F2, =C7=EB=D6=B8=BD=CC!</P></DIV>
59 <P> </P></BODY></HTML>
60
61 ——=_NextPart_002_007C_01C3115F.80DFC5E0–
62
63 ——=_NextPart_001_007B_01C3115F.80DFC5E0
64 Content-Type: image/jpeg; name=”=?gb2312?B?x+fAyrGzvrAuSlBH?=”
65 Content-Transfer-Encoding: base64 66 Content-ID: <007901c3111c$72b978a0$0100007f@bluesky>
67
68 /9j/4AAQSkZJRgABAgEASABIAAD/7QVoUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA
69 AQBIAAAAAQABOEJJTQPzAAAAAAAIAAAAAAAAAAA4QklNBAoAAAAAAAEAADhCSU0nEAAAAAAACgAB
70 AAAAAAAAAAI4QklNA/UAAAAAAEgAL2ZmAAEAbGZmAAYAAAAAAAEAL2ZmAAEAoZmaAAYAAAAAAAEA
… … … …
169 RxVw98Vawq12xQ44q0cKtHFDWKGsKt4EtiuKt4q//9k=
170
171 ——=_NextPart_001_007B_01C3115F.80DFC5E0–
172
173 ——=_NextPart_000_007A_01C3115F.80DFC5E0
174 Content-Type: application/msword; name=”readme.doc”
175 Content-Transfer-Encoding: base64
176 Content-Disposition: attachment; filename=”readme.doc”
177
178 0M8R4KGxGuEAAAAAAAAAAAAAAAAAAAAAPgADAP7/CQAGAAAAAAAAAAAAAAABAAAAJgAAAAAAAAAA
179 EAAAKAAAAAEAAAD+////AAAAACUAAAD/////////////////////////////////////////////
180 ////////////////////////////////////////////////////////////////////////////
… … … …
1688 AAAAAAAAAAAAAAAAAAA=
1689
1690 ——=_NextPart_000_007A_01C3115F.80DFC5E0
1691 Content-Type: application/x-zip-compressed;
1692 name=”=?gb2312?B?tuC0rr/azajQxbXE1LTC6y56aXA=?=”
1693 Content-Transfer-Encoding: base64
1694 Content-Disposition: attachment;
1695 filename=”=?gb2312?B?tuC0rr/azajQxbXE1LTC6y56aXA=?=”
1696
1697 UEsDBBQAAAAIAFKAoi7qOMOvLw0AAABWAAAUAAAAtuC0rr/azajQxbXE1LTC6y5kb2PtXHtwVNUZ
1698 /+4+kk3IQoAkBkRYQkSgbrKb7IYNEMwmm6ckG0jCI0boZneTbJJ9sNlAEsdOtFqd8Z846tQ6PhB1
1699 hrZTJoK0Vhgf1aGt4rMy6D8tdugfTjuOpcBIR9j+vvsIy4YkRNTRen87v/ud53cee+6557vn7L73
… … … …
3125 zajQxbXE1LTC6y5kb2NQSwUGAAAAAAEAAQBCAAAAYQ0AAA==
3126
3127 ——=_NextPart_000_007A_01C3115F.80DFC5E0–
3128

Q 在开始研究MIME邮件的时候,如何得到这样的源码?

A 一些功能比较完善的邮件客户端软件,如微软的Outlook Express,国产的Foxmail等,都提供了查看和保存邮件源码(原始信息)的功能。在Foxmail中,选择邮件列表右键菜单的“原始信息”进行 查看,主菜单的“文件-导出”进行保存。在Outlook Express中,对应的操作分别是“属性”和“另存为”。所保存的.eml文件,可以调用这些程序打开。

Q 请介绍一下MIME邮件的组成?

A 总体来说,MIME消息由消息头和消息体两大部分组成。现在我们关注的是MIME邮件,因此在以下的讨论中姑且称“消息”为“邮件”。在上面的例子中,例 1的1-6行,例2的1—8行,例3的1-18行,是邮件头;例1的8—9行,例2的10—82行,例3的20—3128行,是邮件体。邮件头与邮件体之 间以空行进行分隔,如例1的第7行,例2的第9行,例3的第19行。邮件头中不允许出现空行。有一些邮件不能被邮件客户端软件识别,显示的是原始码,就是 因为首行是空行。

邮件头包含了发件人、收件人、主题、时间、MIME版本、邮件内容的类型等重要信息。每条信息称为一个域,由 域名后加“: ”和信息内容构成,可以是一行,较长的也可以占用多行。域的首行必须“顶头”写,即左边不能有空白字符(空格和制表符);续行则必须以空白字符打头,且第 一个空白字符不是信息本身固有的,解码时要过滤掉。如例2的7-8行,例3的4-5行,13-14行,分别属于一个域。

邮件体包含邮件的内容,它的类型由邮件头的“Content-Type”域指出。常见的简单类型有text/plain(纯文本)和text/html(超文本)。

例2和例3中出现的multipart类型,是MIME邮件的精髓。邮件体被分为多个段,每个段又包含段头和 段体两部分,这两部分之间也以空行分隔。常见的multipart类型有三种:multipart/mixed, multipart/related和multipart/alternative。从它们的名称,不难推知这些类型各自的含义和用处。它们之间的层次关 系可归纳为下图所示:

+------------------------- multipart/mixed ----------------------------+
|                                                                      |
|  +----------------- multipart/related ------------------+            |
|  |                                                      |            |
|  |  +----- multipart/alternative ------+  +----------+  |  +------+  |
|  |  |                                  |  | 内嵌资源 |  |  | 附件 |  |
|  |  |  +------------+  +------------+  |  +----------+  |  +------+  |
|  |  |  | 纯文本正文 |  | 超文本正文 |  |                |            |
|  |  |  +------------+  +------------+  |  +----------+  |  +------+  |
|  |  |                                  |  | 内嵌资源 |  |  | 附件 |  |
|  |  +----------------------------------+  +----------+  |  +------+  |
|  |                                                      |            |
|  +------------------------------------------------------+            |
|                                                                      |
+----------------------------------------------------------------------+

可以看出,如果在邮件中要添加附件,必须定义multipart/mixed段;如果存在内嵌资源,至少要定义 multipart/related段;如果纯文本与超文本共存,至少要定义multipart/alternative段。什么是“至少”?举个例子 说,如果只有纯文本与超文本正文,那么在邮件头中将类型扩大化,定义为multipart/related,甚至multipart/mixed,都是允 许的。

multipart诸类型的共同特征是,在段头指定“boundary”参数字符串,段体内的每个子段以此串 定界。所有的子段都以“–”+boundary行开始,父段则以“–”+boundary+“–”行结束。段与段之间也以空行分隔。在邮件体是 multipart类型的情况下,邮件体的开始部分(第一个“–”+boundary行之前)可以有一些附加的文本行,相当于注释,解码时应忽略。段间 也可以有一些附加的文本行,不会显示出来,如果有兴趣,不妨验证一下。

结合boundary定界和multipart层次关系图,我们分析一下例2和例3的邮件体层次与段嵌套关系。

在例2中,10-12行是附加文本行,13-82行是multipart/alternative型的段,包含两个子段:13-30行是纯文本正文,32-79行是超文本正文。

在例3中,20-21行是附加文本行,22-3127行是multipart/mixed型的段,包含3个子 段:22-171行是multipart/related段,173-1688行与1690-3125行是两个附件。multipart/related 段又包含两个子段:27-61行是multipart/alternative段,63-169行是一个内嵌资源(图片)。multipart /alternative段又包含两个子段:31-48行是纯文本正文,40-59行是超文本正文。

例1只有纯文本正文,实际上属于multipart层次关系图中的一个特殊情况。如果非要避简就繁,写成下面的形式,也是完全符合MIME精神的。

Date: Thu, 18 Apr 2002 09:32:45 +0800
From: <bhw98@sina.com>
To: <bhwang@jlonline.com>
Subject: Test
Mime-Version: 1.0
Content-Type: multipart/alternative; boundary=”{[(^_^)]}” –{[(^_^)]}
Content-Type: text/plain; charset=”iso-8859-1″
Content-Transfer-Encoding: 7bit This is a simple mail. –{[(^_^)]}–

Q 在邮件头和段头中,有哪一些常见的域?

A 在邮件头中,有很多从RFC 822沿用的域名,MIME也增加了一些。常见的标准域名和含义如下

域名 含义 添加者
Received 传输路径 各级邮件服务器
Return-Path 回复地址 目标邮件服务器
Delivered-To 发送地址 目标邮件服务器
Reply-To 回复地址 邮件的创建者
From 发件人地址 邮件的创建者
To 收件人地址 邮件的创建者
Cc 抄送地址 邮件的创建者
Bcc 暗送地址 邮件的创建者
Date 日期和时间 邮件的创建者
Subject 主题 邮件的创建者
Message-ID 消息ID 邮件的创建者
MIME-Version MIME版本 邮件的创建者
Content-Type 内容的类型 邮件的创建者
Content-Transfer-Encoding 内容的传输编码方式 邮件的创建者

非标准的、自定义域名都以X-开头,例如X-Mailer, X-MSMail-Priority等,通常在接收和发送邮件的是同一程序时才能理解它们的意义。

在段头中,大致有如下一些域

域名 含义
Content-Type 段体的类型
Content-Transfer-Encoding 段体的传输编码方式
Content-Disposition 段体的安排方式
Content-ID 段体的ID
Content-Location 段体的位置(路径)
Content-Base 段体的基位置

有 的域除了值之外,还带有参数。值与参数、参数与参数之间以“;”分隔。参数名与参数值之间以“=”分隔。如例3的28-29行,Content-Type 域的值为“multipart/alternative”,此外有一个参数boundary,值 为”—-=_NextPart_002_007C_01C3115F.80DFC5E0″。又如例3的第176行,Content- Disposition域的值为“attachment”,此外有一个参数filename,值为“readme.doc”。

Q Content-Type以及它们的参数有哪些形式?

A Content-Type都是“主类型/子类型”的形式。主类型有text, image, audio, video, application, multipart, message等,分别表示文本、图片、音频、视频、应用、分段、消息等。每个主类型都可能有多个子类型,如text类型就包含plain, html, xml, css等子类型。以X-开头的主类型和子类型,同样表示自定义的类型,未向IANA正式注册,但大多已经约定成俗了。如application/x- zip-compressed是ZIP文件类型。在Windows中,注册表的“HKEY_CLASSES_ROOT\MIME\Database \Content Type”内列举了除multipart之外大部分已知的Content-Type。

关于参数的形式,RFC里有很多补充规定,有的允许带几个参数,较为常见的有

主类型 参数名 含义
text charset 字符集
image name 名称
application name 名称
multipart boundary 边界

其中字符集也能在Windows注册表的“HKEY_CLASSES_ROOT\MIME\Database\Charset”内见到。

Q Content-Transfer-Encoding有哪些?有什么特点?

A Content-Transfer-Encoding共有Base64, Quoted-printable, 7bit, 8bit, Binary等几种。其中7bit是缺省的编码方式。电子邮件源码最初设计为全部是可打印的ASCII码的形式。非ASCII码的文本或数据要编码成要求 的格式,如上面的三个例子。Base64, Quoted-Printable是在非英语国家使用最广使的编码方式。Binary方式只具有象征意义,而没有任何实用价值。

Base64将输入的字符串或一段数据编码成只含有 {‘A’-'Z’, ‘a’-'z’, ’0′-’9′, ‘+’, ‘/’}这64个字符的串,’='用于填充。其编码的方法是,将输入数据流每次取6 bit,用此6 bit的值(0-63)作为索引去查表,输出相应字符。这样,每3个字节将编码为4个字符(3×8 → 4×6);不满4个字符的以’='填充。有的场合,以“=?charset?B?xxxxxxxx?=”表示xxxxxxxx是Base64编码,且原文 的字符集是charset。如例3第7行”=?gb2312?B?wLbAtrXEzOwNCg==?=”是由简体中文“蓝蓝的天”编码而成的。在段体内 则直接编码,适当时机换行,MIME建议每行最多76个字符。如例3的1697-3125行,是一个ZIP文件的Base64编码。

Quoted-printable根据输入的字符串或字节 范围进行编码,若是不需编码的字符,直接输出;若需要编码,则先输出’=',后面跟着以2个字符表示的十六进制字节值。有的场合,以 “=?charset?Q?xxxxxxxx?=”表示xxxxxxxx是Quoted-printable编码,且原文的字符集是charset。在段 体内则直接编码,适当时机换行,换行前额外输出一个’='。如例3的44-59行,是HTML文本的Quoted-printable编码。其中第45行 “=C7=E7=C0=CA”原文是“晴朗”,因为“晴”的GB2312码是C7E7,“朗”的GB2312码是C0CA。第48、53、57行末尾只有 孤零零的’=',表示这是由编码造成的软回车,而非原文固有的。

近年来,国内多数邮件服务器已经支持8bit方式,因此只在国内传输的邮件,特别是在邮件头中,可直接使用8bit编码,对汉字不做处理。如果邮件要出国,还是老老实实地按Base64或Quoted-printable编码才行。

Q 什么是内嵌资源?它有哪些形式?

A 内嵌资源也是MIME的一个发光点,它能使邮件内容变得生动活泼、丰富多彩。可在邮件的multipart/related框架内定义一些与正文关联的图 片、动画、声音甚至CSS样式和脚本的段。通常在HTML正文内,使用超级链接与内嵌资源相联系。如在例3中,HTML正文53-54行,解码后为

<BODY background=cid:007901c3111c$72b978a0$0100007f@bluesky bgColor=#ffffff>

它指出用一个Content-ID为007901c3111c$72b978a0$0100007f@bluesky的图片作为背景(cid:xxxxxxxx也是一种超级链接)。而64-169行恰好就是这样一个内嵌资源。

除了用Content-ID进行联系外,还有另外一种常用形式:用普通超级连接和Content-Location。例如:

在HTML正文中,

… … … … <
IMG SRC=”http://www.dangdang.com/images/all/anti_joyo_dm_book.gif”>
… … … … <
IMG SRC=”http://www.dangdang.com/dd2001/getimage_small.asp?id=486341″>
… … … …

对应的内嵌资源为

Content-Type: image/gif; name=”anti_joyo_dm_book.gif”
Content-Transfer-Encoding: base64
Content-Location: http://www.dangdang.com/images/all/anti_joyo_dm_book.gif
… … … …
Content-Type: application/octet-stream; name=”getimage_small.asp?id=486341″
Content-Transfer-Encoding: base64
Content-Location: http://www.dangdang.com/dd2001/getimage_small.asp?id=486341
… … … …

另外,

Content-Location: http://www.dangdang.com/images/all/anti_joyo_dm_book.gif

Content-Location: anti_joyo_dm_book.gif Content-Base: http://www.dangdang.com/images/all/

是等效的。

Q 邮件病毒如何利用附件和内嵌资源传播?

A 有的邮件附件可能带有病毒,容易理解。附件毕竟是文件,也好预防,不轻易打开就是了。但内嵌资源是在浏览邮件内容时就要访问的,若其中藏有病毒或恶意代码,你在不知不觉中就中招了。如前两年曾经在全球范围内流行的Nimda病毒,功能性源码如下:

MIME-Version: 1.0
Content-Type: multipart/related; type=”multipart/alternative”; boundary=”====_ABC1234567890DEF_====”

–====_ABC1234567890DEF_====
Content-Type: multipart/alternative; boundary=”====_ABC0987654321DEF_====”

–====_ABC0987654321DEF_====
Content-Type: text/html; charset=”iso-8859-1″
Content-Transfer-Encoding: 7bit <HTML><HEAD></HEAD><BODY bgColor=#ffffff> <iframe src=cid:EA4DMGBP9p height=0 width=0> </iframe></BODY></HTML>

–====_ABC0987654321DEF_====–

–====_ABC1234567890DEF_====
Content-Type: audio/x-wav; name=”readme.exe”
Content-Transfer-Encoding: base64 Content-ID: <EA4DMGBP9p> TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAA2AAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFtIGNhbm5vdCBiZSBydW4gaW4gRE9TIG1v ZGUuDQ0KJAAAAAAAAAA11CFvcbVPPHG1TzxxtU88E6pcPHW1TzyZqkU8dbVPPJmqSzxytU88cbVO
… … … … … … … …
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=

–====_ABC1234567890DEF_====

它 将一个可执行文件作为资源嵌入了框架型页面,却声明这段可执行代码是波形声音类型。由于当时微软的IE(版本5.0及以下)存在重大安全漏洞,没有检查 Content-Type与name的扩展名是否匹配,于是就被轻易骗过了,致使点选或打开邮件时自动运行了这个“readme.exe”,机器就感染上 病毒。带毒的机器利用地址簿向别人发送带毒的邮件,一传十,十传百,Nimda蠕虫大行其道。

纵观历史,病毒刚出来时是厉害,但没有任何一种能够持续肆虐下去。Nimda如此,SARS亦当如此。曰:“多难兴邦,众志成城”,又曰:“非典终将倒下,城市精神永存”,相信我们定能很快战胜“非典”!

病毒库升级是跟在新病毒屁股后进行的,不要过分依赖杀毒软件。一个良好的习惯是关闭邮件预览功能,或者设定预览纯文本部分,先查看邮件源码,确信排除病毒嫌疑后再打开。对陌生人发来的带超文本正文的邮件,尤其要当心。永远不要在邮件客户端软件内直接打开附件。

Q 一些垃圾邮件采取隐藏发件人的方式,如何追查它们来自哪里?

A 从上面的邮件头域名表中可以看出,邮件的创建者可以掌握大部分的域的内容,但Received等域由各级服务器自动添加,发件人是鞭长莫及。垃圾邮件一般 采用了群发软件发送,邮件头的From域(发件人地址)可以任意伪造,甚至写成收件人地址(收到了自己并没有发过的垃圾邮件,气愤吧?)。查看 Received域(传输路径)链可以找到真正的出处。每个服务器添加的Received语句都在邮件首,故最下面一个Received就包含了发件人所 用的SMTP或HTTP服务器,及最初的网关外部IP地址。

Receive语句的基本格式是:from A by B。A为发送方,B为接收方。例如:

Received: (qmail 45304 invoked from network); 4 May 2003 17:05:47 -0000 Received: from unknown (HELO bjapp9.163.net) (202.108.255.197) by 202.106.182.244 with SMTP; 4 May 2003 17:05:47 -0000 Received: from localhost (localhost [127.0.0.1]) by bjapp9.163.net (Postfix) with SMTP id E1C761D84C631 for <bhw98@sina.com>; Mon, 5 May 2003 01:07:26 +0800 (CST) Received: from fanyingxxxx@tom.com (unknown [211.99.162.194]) by bjapp9.163.net (Coremail) with SMTP id OgEAAM1ItT7MNaLC.1 for <bhw98@sina.com>; Mon, 05 May 2003 01:07:26 +0800 (CST)

从 上面的例子中不难看出,该邮件的传输路径是:211.99.162.194 → bjapp9.163.net (Coremail 202.108.255.197?) → bjapp9.163.net (Postfix, 202.108.255.197?) → 202.106.182.244。恰好出现了发件人邮箱fanyingxxxx@tom.com,但多数情况不一定能列出来。

此例的localhost [127.0.0.1],意味着bjapp9.163.net上安装了邮件服务代理性质的软件。

kindle 4 体验及亚马逊买书推送kindle问题

2012年1月1日到手的kindle 4,也是新年新气象,2012多看书的好兆头。2011记录里只记下屈指可数的几本看过的书,这叫人情何以堪。

还是先说问题:

Kindle无法购买Amazon书籍问题

入手kindle总是先折腾一遍功能。看完用户指导,自己翻腾着按几遍按钮,基本功能就用的比较熟了。但是每次按shop in kindle store 总是显示 no item found.。不管是找book、magazine还是其他,通通没有内容。检查wifi又是正常连接的。这到底是为什么呢?

然后再上Amazon官网,用注册时的账户登录,发现在网上也无法购买书籍,更不要说买书后推送到kindle上了!

怎么办?于是四处找解决方案,各中论坛百度知道之类的网站找。没找到明确的方案,但是,看到说亚马逊买书不支持中国大陆!于是就猜能不能假装在国外。而且也确实看到一些教程在注册的时候填入的不是本国地址。

接着,解决办法就要出来了。我试着改变帐号信息,提交一个美国的地址,kindle 和 amazon网站的账户就能买书了!成功买了本免费的ebook推送到kindle上!其实账号信息在一开始注册amazon账号的时候就会填写,如果那时没填或者填写了国内的地址,那就会导致没法买书。

解决办法具体步骤

登陆amazon.com,点击右上角的your account。没登陆的会跳转到登陆页面,输入邮箱密码,成功跳转。新页面中找到setting 项,点击manage address book. 如下图:

跳转出如下页,点击edit。

在这个页面输入地址。找个美国的地址输入就可以了,比如某某公司地址。。。大概正确就行,点击save后amazon会很人性化的给你提示说哪里写的不合适,让你选择是否使用amazon提示修正的地址。

统一保存,然后大功告成。就可以买书了!!!

购买,然后your account -> manage your kindle -> books

右方action点击后有菜单,选择推送到kindle。

 

 

Kindle 4体验感受

纯粹一看书的工具,用来看书足够了,也只能用来看书。要想玩其他请买kindle fire 或者ipad。

贴膜确实会影响阅读效果,反光挺讨厌的。

经历过一次死机,白屏毫无反应。于是长按关机键重启搞定。

邮箱推送书籍,不用改free.kindle.com的邮箱,直接使用默认的邮箱就行了。

关了灯就不能看kindle有点麻烦,习惯了窝床上熄灯用手机看书一时改不过来。

看中了超长待机和点纸书买的,挺好,还督促我多看书!

 

2011看的书电影电视还有玩的

2011

电影

doomsday(末日侵袭)
非诚勿扰2
让子弹飞
大笑江湖
赵氏孤儿
创·战纪
将爱情进行到底
发条橙
let me in (American)
welcome to rileys
the kids are all right
致命伴侣
预产期 Due Date
国王的演讲 The King’s Speech
黑天鹅 Black swan
急速复仇
城中大盗 the town
爱情与灵药 love&other drugs
狼人 the wolfman 20110314
开心鬼上身 车太贤 20110316
女巫的季节 20110317
哈利波特之死亡圣器(上)20110416
黄色20110416
爱,不爱 201104
神奇侠侣 201104
不求回报Cold Spring Picture 201104
婚前试爱 201104
单身男女
新倩女幽魂
倩女幽魂123
速度与激情123
rango 兰戈 20110528
我的黑色迷你裙 20110530
速度与激情45
X战警 第一战
X战警 123
生化危机3 20110724
白夜行20110726
我是传奇
时间旅行者的妻子
大侦探福尔摩斯
求婚大作战sp
源代码
财神客栈
窃听风云2
狂野目标 20111021
失恋33天20111108
猩球崛起20111117
钢的琴20111120
我们所知道的生活20111204
魔法奇幻秀20111213
金陵十三钗20111220
幸福终点站20111224
美剧英剧:
行尸走肉第一季
权利的游戏第一季
妖女迷行第一季
妖女迷行第二季
吸血鬼日记第二季
吸血鬼日记第三季
生活大爆炸第四季
生活大爆炸第五季
绯闻女孩第四季
绯闻女孩第五季
裂痕第一季
裂痕第二季
裂痕第三季
裂痕第四季

六尺之下第一季
六尺之下第二季
妙贼警探第一季
妙贼警探第二季
妙贼警探第三季
尼基塔第一季
尼基塔第二季

日剧:
白夜行
求婚大作战
野猪大改造
海贼王前200集

韩剧:
秘密花园
城市猎人

港剧:
笑傲江湖(吕颂贤)应该是这个版本的第三遍了。
2011

巨流河 齐邦媛 201104
娱乐至死 尼尔・波兹曼 201104
九型人格 201105
经济学史300年 201106
货币战争1 201109
货币战争2 201110

欧洲 一堂丰富的人文课 201110
浪潮之巅201111
货币崛起201111
货币战争3 201111

冰与火之歌 权利的游戏201112
乔布斯传201112
2011

1.31~2.11 春节(张家港)
2.19 兔年梧桐山踏青
3.20 磨房百公里
4.4 东部华侨城大峡谷
4.9 七娘山
4.30~5.1 广州
5.6~9 张家港
5.14 测试部素质拓展 玫瑰海岸
6.4~8 昆明丽江
7.2 梧桐山-二线关-谭仙庙-圆山公园后山-木瓜小屋-三州田-盐田徒步
7.11~17 北京
8.6 大康溪谷溯溪
8.12~13 露营(香港海下湾海岸公园潜浮)
8.27 东西冲穿越
9.5~8广州
9.9~13 菲律宾
10.23 光明农场
10.29 西贡村-红花岭-抛狗岭-半云天徒步
11.6 山友八周年-走进马峦山50公里徒步
11.25~27 第四届丹霞山徒步(韶关)
12.9~11 山友山野百里(信宜)蓝坑村-石牛肚-猫耳石-公婆石-十二灶顶-大营坳
12.16~17 东部华侨城茶溪谷
12.25 三水线穿越

20120102HK

这是我第二次到香港,第一次只去湾下海海岸公园露营潜浮,还有就西贡某条街呆了一个小时。所以,可以说我没去过hk。。。

为了说起来我确实像是来过香港而不是招摇撞骗的,不得已,我得再来一次认认路。于是,这次hk之旅就像第一次去广州一样是暴走。记录以下路线图。。。

从深圳湾口岸入境。谷歌地图上查南航公司有辆公交到,结果没有。走到桂庙新村公交站,最早一班到深圳湾口岸的公交是6:30发车,到桂庙要7点出头。过关,坐B3X到红桥,转960到湾仔轩尼诗道上的菲明林道下,9点出头。差不多下图右边的蓝点,然后往铜锣湾方向走,绕了下维多利亚公园,香港中央图书馆。然后往回走去铜锣湾的Sogo和世贸中心,到10点终于开门。9点半的时候路过那里GUCCI和PRADA的专卖店,看到外面一票漂亮妹子在等开门,大半嘴里叼了根烟。10点回来,一看,原来都是服务员,不是等开门扫货的。。。

然后往东走,湾仔,金钟,中环,上环。什么湾仔运动场,码头,保时捷专卖店,维多利亚港南岸海边,会展中心,湾仔市政中心,某艺术馆,太古广场,金钟市政中心,香港区政府,各种大楼,皇后大道,兰桂坊,置地广场,周围一片闹市。

看到穆斯林女性,围着头巾。但是,年轻的围着黑头巾,穿的是hiphop,牛仔裤的裆掉到膝盖。经常看到大厦外某角落藏着一妹子,着装时尚前卫,发呆、玩手机、打电话,一只手里面必然叼着一支烟。金钟到中环之间,各个公园都被东南亚的妹子阿姨占领了。。。

 

然后在中环做地铁到旺角,绕一圈,然后油麻地,尖沙咀,新港中心,海港城,维多利亚港看看,星光大道,再去红磡坐地铁到罗湖。回家。

一堆ICAC,但是比起周生生周大福的店就少太多太多了。