Working with James, Part 2: 用matchers 和 mailets构建基

JMail操作详解apache-james-2.3.2.zip 附带apache-james-2.3.2.zip和JMail示例代码很经典入门必备 立即下载
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script> 增加两个新的APIs增强这个e-mail服务器 级别: 中级 Claude Duguay (claude.duguay@verizon.net) Chief Architect, Arcessa, Inc. June 10, 2003 这是讨论用Apache组织提供的James邮件服务器开发应用程序的第二篇文章。这篇文章的内容超出了James基础设施这些基础知识的介绍,它实现了一个实际的应用程序。通过将用户状态定义为available 和 unavailable,程序可以为那些将自己的状态设置为 unavailable 的用户自动答复收到的邮件,而且用户可以对定制自己的答复邮件。 这篇文章是探索 Java Apache Mail Enterprise Server,即James的第二部分。在这个系列的第一篇文章中,我们了解了James的基础设施和能力等基础知识,并且进行了在实验系统上安装James的整个过程。在这篇文章中,我们会在James基础设施上实现一个想法,开发一个支持用户账户的unavailable状态的应用程序。要使用我们的应用程序,用户需要发送指定类型的邮件到一个指定的邮件服务器地址,这个邮件被作为任何收到的邮件的自动答复消息,直到用户发送一个邮件撤销他的不可到达状态。这一机制与邮件客户端程序中常用的方法类似,向发件人发送一封邮件表示用户现在不在,因为去度假或者其它什么原因。但除非用户一直让客户端程序开着,否则这个功能没什么用。 通过使用服务器端解决方案,你可以在度假的时候用任何客户端软件登录服务器,在任何时候改变你的自动答复消息。 应用程序设计 在进行设计之前,我们应该清楚的说明需求。下面的几点将作为我们的例子设计的根据: 用户能够通过发送e-mail到 unavailable@emailserver to 来将他的账户切换到不可到达模式。发送到unavailable@emailserver的消息要存下来以备将来使用。 如果已经存在这个用户的不可到达消息,原来的消息将被新的覆盖,但用户会收到所发生的一切情况的通知。 用户能够通过发送e-mail 到 available@emailserver 来取消所有的不可到达消息。发送到 available@emailserver的消息会被丢弃并移走原来保存的不可到达消息 。用户应该收到账户状态已经变为可以到达的通知。 一个保存了不可到达消息的用户在任何时候收到的e-mail都应该用保存的消息自动回复,以向发件人说明用户当前处于不可到达的状态。触发这个操作的原始邮件应该进行正常的处理。 理解James基础设施 这个系列的第一篇 向你介绍了James的基础设施和它所具有的能力。 我用三段话来描述需求并不是偶然的。每个需求都直接对应着特定情形下的一组操作。每种情形都应该有相应的匹配器进行识别。( 参阅 第一篇 了解匹配器和mailet的详细信息) 例如,发送到特定地址的e-mail能用原有的RecipientIs匹配器进行匹配。但当我研究RecipientIs 的源代码时,我注意到它能处理任意数量的接收者,并且与其中任何一个接收者相匹配都被认为是匹配的。可能在大多数情况下,这样的处理很好,但这对于我们的应用而言是不幸的。我们的应用要求确保一个并且仅有一个特定地址包含在接收者中,所以我们要开发一个简单的匹配器来完成这个任务。我们将要开发的 MatchSingleRecipient 类还将向你展示如何让Matcher API发挥作用。 识别已经保存了准备用于处理的不可到达消息的接收者要稍微复杂一点儿。因此,我们要开发一个 MatchUnavailableUser 匹配器。 为了使匹配操作更有效,我们在测试不可到达目录中保存的文件之前先检查接收者是否是本地用户。另外,e-mail的处理也应该是相当简单的。接下来,我们先开发两个匹配器类,然后进行 mailet的开发。 我们对不可到达目录的使用相当多。实际上,需要对不可到达目录实现几个操作,包括检测消息是否存在、在该目录中保存、读取和删除消息。因为每个功能都需要知道保存消息的目录的地址和相关用户的一些信息,所以我们创建了一个独立的MatchUnavailableUser匹配器类来获取这些信息。我们设计的mailet实现类也用到了它。 我们要实现的匹配器几乎没有相同的地方,但处理我们提出的需求的mailet(每个需求都有一个mailet)都需要相似的配置信息和访问不可到达目录。所以我们用了一个每个mailet都能扩展的基类。除了提供基本的初始化代码,基类还是放置几个子类共用的应用方法的好地方。我们定义的基类是 UnavailableUserBase。 这三个应用功能将由我们的mailet类-- UnavailableMessageSave, UnavailableMessageDrop, 和 UnavailableMessageSend 来处理。前两个mailet功能相似,并且都是对一个接收者地址--可到达的和不可到达的--进行操作,所以它们共用了一些代码,这些共用的代码放在超类中。UnavailableMessageSend mailet是最复杂的一个,主要是因为它要处理多个接收者地址,还要给每个发送消息到不可到达的接收者的发件人发送消息。幸运的是,用Matcher 和 Mailet API 工作比较容易。 编写匹配器 基类 GenericMatcher简化了在James中编写匹配器的工作,大多数实现类都会扩展这个基类。我们的两个匹配器都扩展了这个类。首先,我们要在init() 方法中得到配置信息,然后在match()方法中执行处理动作。从技术上来讲,我们应该实现getMatcherInfo() 方法来报告卖主、版本等信息,但为了让这个例子中的代码更简练,我没有做这些事情。 在James的配置文件config.xml (我们已经在这个系列的第一篇中详细讨论了这个文件)中配置一个匹配器时,我们用一个XML 属性来说明它。匹配器的类名后跟着一个等号和一些文本信息;这些文本信息可以用getCondition() 方法获得。为了利用James提供的邮件地址比较代码,我们用getCondition() 方法返回的值创建了一个实例并把它保存到一个实例变量中。不用说,列表1中的MatchSingleRecipient 需要一个单独有效的本地e-mail地址作为它唯一的参数。 match() 方法得到被处理的e-mail接收者列表 。Mail 对象提供了几个有趣的方法。其中最常用的是getRecipients(),该方法返回一个包含了MailAddress 实例的 Java Collection 对象。为了看看我们是否有一个匹配的结果,首先要通过检查Collection 对象的大小来确信只有一个接收者,然后确保Collection (长度为1)对象包含的地址是我们在配置文件中说明的地址。 要编译这些类,你要保证已经下载了在本系列的第一篇文章中列出的所有组件,你应该在你的 classpath中包含JavaMail (mail.jar) 和 JavaBeans Activation Framework (activation.jar) JAR 文件,还有james.jar文件。如果你找不到 james.jar文件,可以解压James-2.1.2/apps目录下的James.SAR文件。 列表1. MatchSingleRecipient: 识别发送到某一指定地址的e-mail package com.claudeduguay.mailets; import java.util.*; import javax.mail.*; import org.apache.mailet.*; public class MatchSingleRecipient extends GenericMatcher { protected MailAddress addressToMatch; public void init(MatcherConfig config) throws MessagingException { super.init(config); addressToMatch = new MailAddress(getCondition()); } public Collection match(Mail mail) throws MessagingException { Collection recipients = mail.getRecipients(); if (recipients.size() == 1 && recipients.contains(addressToMatch)) { return recipients; } return null; } } 列表2中所示的MatchUnavailableUser 类,使用了 UnavailableStore 类,我们一会儿就会介绍到它。为了让它发挥作用,我们需求通过 getCondition() 方法来检索用来存储不可到达消息的目录。 列表2. MatchUnavailableUser: 识别不可到达用户 package com.claudeduguay.mailets; import java.util.*; import javax.mail.*; import org.apache.mailet.*; public class MatchUnavailableUser extends GenericMatcher { protected UnavailableStore store; public void init(MatcherConfig config) throws MessagingException { super.init(config); String folder = getCondition(); store = new UnavailableStore(folder); } protected boolean isLocalAddress(MailAddress address) { String host = address.getHost(); MailetContext context = getMailetContext(); return context.isLocalServer(host); } protected boolean isUserUnavailable(MailAddress address) { return store.userMessageExists(address); } public Collection match(Mail mail) throws MessagingException { Collection matches = new Vector(); Collection recipients = mail.getRecipients(); Iterator iterator = recipients.iterator(); while (iterator.hasNext()) { MailAddress address = (MailAddress)iterator.next(); String user = address.getUser(); if (isLocalAddress(address) && isUserUnavailable(address)) { matches.add(address); } } return matches; } } 为了使 match() 方法容易实现,我又实现了两个应用方法: isLocalAddress(),它调用了 MailetContext的 isLocalServer() 方法来判断接收者是否为本地用户;isUserUnavailable(),这个方法用UnavailableStore的 userMessageExists() 方法来判断用户是否已经说明了一个不可到达消息。 match 方法创建了一个Collection 对象 (一个 Vector) 来收集应该被 mailet 处理的接收者。然后遍历接收者并逐一检查它是否为本地地址、是否已经说明了该用户的不可到达消息。如果这两个条件都为真,match将这个地址添加到接收者列表中,处理结束后返回这个列表。 这就是我们的匹配器的全部内容。让我们快速的看一下列表3中的UnavailableStore代码,MatchUnavailableUser 类和我们实现的每个 mailet 类都用到了它。这种设计思想是将与访问不可到达消息存储相关的所有方法都收集到一个类中。这样,如果必要的话,就可以开发更复杂的实现方法。这个版本有意的将这个类实现的很简单,并且仅仅将所有用户的消息存储到一个单一的目录中。如果你要在服务器上管理几千个用户,这可能是个问题。但对于大多数应用来说,这种处理足够了。 列表3. UnavailableStore: 访问不可到达消息的存储 package com.claudeduguay.mailets; import java.io.*; import java.util.*; import javax.mail.*; import javax.mail.internet.*; import org.apache.mailet.*; public class UnavailableStore { protected File home; public UnavailableStore(String folder) { home = new File(folder); if (!home.exists()) { home.mkdirs(); } } public File getUserMessageFile(MailAddress address) { String user = address.getUser(); File file = new File(home, user ".msg"); return file; } public boolean userMessageExists(MailAddress address) { return getUserMessageFile(address).exists(); } public void deleteMessage(MailAddress address) { getUserMessageFile(address).delete(); } public void storeMessage(MailAddress address, MimeMessage msg) throws MessagingException, IOException { File file = getUserMessageFile(address); FileOutputStream out = new FileOutputStream(file); msg.writeTo(out); out.close(); } public MimeMessage getMessage(MailAddress address) throws MessagingException, IOException { File file = getUserMessageFile(address); Properties props = System.getProperties(); Session session = Session.getDefaultInstance(props); FileInputStream in = new FileInputStream(file); MimeMessage msg = new MimeMessage(session, in); in.close(); return msg; } } UnavailableStore 中的关键配置参数是查找文件的目录。我们通过构造方法将这个值传送到类中,并且,如果这个目录不存在就创建它。为了保证程序正确运行,必须确保在config.xml文件中所有的匹配器和mailet的这一配置参数指向同一个目录。 其余的方法主要是用于访问文件。getUserMessageFile() 方法为解析与给定用户相对应的文件名提供了通用的办法。我们用James MailAddress 对象用作这些方法的参数,因为它在我们的匹配器和mailet代码中很好用。文件名的格式为[不可到达目录]/[用户名].msg. MimeMessage 对象是 JavaMail API中的一部分。James 在它自己的基础设施中借用了这些对象,所以我们能用相同的API。 storeMessage() 和 getMessage() 方法利用了 MimeMessage 在标准的文本格式(大多数邮件服务器使用的格式)中读写消息的能力。虽然使用串行化对象的格式一样容易(并且可能更高效),但消息是可读的文本格式时调试起来更容易。 编写mailets 现在我们有了识别需要处理的e-mail的机制(匹配器),接下来我们还需要通过实现mailet类来将处理元素集成到一起。我们要借用 UnavailableStore 来存储和访问不可到达消息。 在开始实现mailet之前,我们先快速浏览一下实现了通用方法的基类。mailet 的配置参数以XML标签的形式保存在config.xml 文件中。这些标签可以用我们扩展的GenericMailet类中的 getInitParameter() 方法获得。列表4中列出的UnavailableMessageBase 类被声明为abstract的,因为它不直接实现服务方法。 init() 方法保存了一个UnavailableStore 对象的引用,这与MatchUnavailableUser 类中的init() 方法类似。 UnavailableMessageBase 类中的大多数代码都是应用方法。这些方法包括:将一个MailAddress 和一个 Address 对象矩阵相互转化、在一个地址集合中取得第一个MailAddress 、将一个MailAddress打包为一个集合,以及两个创建e-mail消息的方法。 因为消息可能包含任意部分内容,所以最后的 createMessage() 方法用了一个Object和String参数分别说明内容和MIME类型。简单的情况下,用一个字符串说明内容,用一个简化的标记抽象表示 MIME 类型"text/plain" 。我们用更普通的方法发送不可到达消息,因为用户存储的消息的复杂性可能是任意的。 列表4. UnavailableMessageBase: 实现公用方法的基类 package com.claudeduguay.mailets; import java.util.*; import javax.mail.*; import javax.mail.internet.*; import org.apache.mailet.*; public abstract class UnavailableMessageBase extends GenericMailet { protected UnavailableStore store; public void init(MailetConfig config) throws MessagingException { super.init(config); MailetContext context = config.getMailetContext(); String folder = getInitParameter("folder"); store = new UnavailableStore(folder); } protected Address[] toAddressArray(MailAddress address) throws AddressException { InternetAddress[] array = new InternetAddress[1]; array[0] = address.toInternetAddress(); return array; } protected MailAddress getFirstAddress(Collection list) { Iterator iterator = list.iterator(); return (MailAddress)iterator.next(); } protected Collection addressAsCollection(MailAddress address) { Collection list = new Vector(); list.add(address); return list; } protected MimeMessage createMessage( MailAddress from, MailAddress to, String subject, String text) throws MessagingException { return createMessage(from, to, subject, text, "text/plain"); } protected MimeMessage createMessage( MailAddress from, MailAddress to, String subject, Object content, String type) throws MessagingException { Properties props = System.getProperties(); Session session = Session.getDefaultInstance(props); MimeMessage msg = new MimeMessage(session); msg.addFrom(toAddressArray(from)); msg.addRecipients(Message.RecipientType.TO, toAddressArray(to)); msg.setSubject(subject); msg.setContent(content, type); return msg; } } 现在我们能够直接在mailets上工作了。要做的第一件事情就是保存发送到不可到达地址的消息。我们能够配置匹配器 MatchSingleRecipient 将与不可到达的接收者匹配的消息转发给 UnavailableMessageSave mailet,如 列表5所示。为了使可配置能力最大化,我已经将说明配置消息的主题和内容字符串变成可能的了。这些值存储在 init() 方法的局部变量中。 service 方法做了所有的工作。因为我们扩展了基类UnavailableMessageBase,所以我们能够访问 UnavailableStore的一个实例。我们的目标是得出谁发送了消息,得到要存储的MimeMessage 并把它保存到正确的目录下,向发件人发送一个确认e-mail。我们可以假设发件人地址是有效的,如果它无效,匹配器是不会允许消息通过的。 注意我们处理异常的方式。log() 方法被用来确保报告出现的问题,但如果你没看到你期望的行为,必须去检查日志文件。另外,注意我们将e-mail的状态设置为GHOST,停止了对接收到的e-mail的进一步的处理。因为我们自己保存了它,所以不再需要e-mail服务器执行额外的处理。 列表5. UnavailableMessageSave: 保存发送到unavailable@emailserver的消息 package com.claudeduguay.mailets; import java.io.*; import java.util.*; import javax.mail.*; import javax.mail.internet.*; import org.apache.mailet.*; public class UnavailableMessageSave extends UnavailableMessageBase { protected String subject; protected String content; public void init(MailetConfig config) throws MessagingException { super.init(config); subject = getInitParameter("subject"); content = getInitParameter("content"); } public void service(Mail mail) throws MessagingException { MailAddress sender = mail.getSender(); Collection recipients = mail.getRecipients(); MailAddress address = getFirstAddress(recipients); MailetContext context = getMailetContext(); try { MimeMessage msg = (MimeMessage)mail.getMessage(); store.storeMessage(sender, msg); mail.setState(Mail.GHOST); } catch (IOException e) { log("Unable to store user message", e); } try { MimeMessage msg = createMessage(address, sender, subject, content); Collection target = addressAsCollection(sender); context.sendMail(address, target, msg); } catch (MessagingException e) { log("Unable to send confirmation message", e); } } } 下一个要看的类是 UnavailableMessageDrop mailet,如列表6所示。这个mailet和UnavailableMessageSave非常相似,但它在发送确认消息之前删除而不是保存消息,所以它的代码少一点。在两种情况下,我们都借用了 UnavailableStore 类来访问不可到达消息的存储。 列表6. UnavailableMessageDrop: 删除不可到达的消息 package com.claudeduguay.mailets; import java.io.*; import java.util.*; import javax.mail.*; import javax.mail.internet.*; import org.apache.mailet.*; public class UnavailableMessageDrop extends UnavailableMessageBase { protected String subject; protected String content; public void init(MailetConfig config) throws MessagingException { super.init(config); subject = getInitParameter("subject"); content = getInitParameter("content"); } public void service(Mail mail) throws MessagingException { MailAddress sender = mail.getSender(); Collection recipients = mail.getRecipients(); MailAddress address = getFirstAddress(recipients); MailetContext context = getMailetContext(); store.deleteMessage(sender); mail.setState(Mail.GHOST); try { MimeMessage msg = createMessage(address, sender, subject, content); Collection target = addressAsCollection(sender); context.sendMail(address, target, msg); } catch (MessagingException e) { log("Unable to send confirmation message", e); } } } 列表7中的UnavailableMessageSend mailet是最复杂的,但即使这样你也会看到Mailet API 使这类工作相当简单。init() 在处理给定用户接收到的消息时可以忽略一个地址列表中的地址。为了避免将确认消息发送给用户时产生循环,这是很必要的。在我们的配置中设定了两个地址 --一个用于可到达状态,一个用于不可到达状态 -- 将被忽略的。我已经将这个设定做成可配置的,管理员可以选择使用不同的地址。 地址列表是一个用分号分割的字符串表示的。 我将UnavailableStore 类中的方法 getMessage() 引入到这个类中来记录读取消息时产生的任何问题,并且加了一个 isIgnorable() 方法来检查MailAddress 是否包含在可忽略列表中。这些工作都在service 方法中完成。 列表7. UnavailableMessageSend: 将不可到达的消息发送给发件人 package com.claudeduguay.mailets; import java.io.*; import java.util.*; import javax.mail.*; import javax.mail.internet.*; import org.apache.mailet.*; public class UnavailableMessageSend extends UnavailableMessageBase { protected MailAddress[] ignore; protected MimeMessage getMessage(MailAddress address) { try { return store.getMessage(address); } catch (Exception e) { log("Unable to read stored e-mail message: ", e); } return null; } public void init(MailetConfig config) throws MessagingException { super.init(config); String skip = getInitParameter("skip"); StringTokenizer tokenizer = new StringTokenizer(skip, ";", false); int count = tokenizer.countTokens(); ignore = new MailAddress[count]; for (int i = 0; i < count; i ) { String address = tokenizer.nextToken().trim(); ignore[i] = new MailAddress(address); } } protected boolean isIgnorable(MailAddress address) { for (int i = 0; i < ignore.length; i ) { if (address.equals(ignore[i])) { return true; } } return false; } public void service(Mail mail) throws MessagingException { MailAddress sender = mail.getSender(); MailetContext context = getMailetContext(); Collection recipients = mail.getRecipients(); Iterator iterator = recipients.iterator(); while (iterator.hasNext()) { MailAddress address = (MailAddress)iterator.next(); // If the recipient is unavailable, send the message. if (!isIgnorable(sender) && store.userMessageExists(address)) { Collection target = addressAsCollection(sender); MimeMessage msg = getMessage(address); if (msg != null) { try { msg = createMessage(address, sender, msg.getSubject(), msg.getContent(), msg.getContentType()); // Send e-mail from unavailable recipient, to sender context.sendMail(address, target, msg); } catch (IOException e) { log("Unable to construct new message: ", e); } } } } } } UnavailableMessageSend 服务方法需要检查所有的接收者来和保存了不可到达消息的用户匹配。我们用了两个方法来测试每个接收者。isIgnorable() 方法用来检查接收者地址是否可以忽略,UnavailableStore 类中的 userMessageExists() 方法检查这个接收者是否是一个存储了不可到达消息的用户。如果这些条件都满足,我们就检索这个接收者的不可到达消息,用原来存储的主题和内容创建一个新消息,然后把它发送给最初的发件人。 构建和部署 构建这个项目中的类相当简单,但部署它们却比较复杂。只要在classpath中包含 JavaMail (mail.jar)、JavaBeans Activation Framework (activation.jar -- JavaMail API需要这个文件)、James (james.jar),我们就可以很容易的构建这些类。要用 James JAR 文件,你必须从 james.sar 文件中将它释放出来,解压james.sar文件后你可以在james/apps 目录下发现这个jar文件。 ( 在资源中你可以找到下载这些包的链接,本系列的第一篇文章有关于安装的详细信息。) SAR文件 (Server Application Resource)是Phoenix中提出的一个概念。 我们曾经说过,James是运行在 Avalon项目开发的Phoenix 服务器基础设施中的。(查看 资源 了解 Avalon.的详细信息) Phoenix 为 Java 平台的项目提供了一个通用的服务器框架。 SAR 文件是一个带有结构说明的 JAR 文件 (压缩文件)。 我们所需要的 james.jar文件在SAR档案文件的 SAR-INF/lib子目录下。可以用任何合适的应用程序,比如 WinZIP 或者UNIX 下的解压缩应用程序,解压SAR文件后得到它。 很不幸,将mailet添加到James包中的唯一可选的办法就是重新创建SAR文件。其实这是一个笨办法,而且也不应该这么复杂,好在James 开发组已经意识到这样很麻烦并正在打算改善这种状况。然而,现在我们只有解压整个james.sar文件才能用它工作。解压后,将我们的类文件放进SAR-INF/lib 目录(也可以打包成JAR文件后放进这个目录),然后修改 James 的配置文件,以便我们的代码能被正确的识别和使用。接着,我们要重新打包 james.sar 文件。为了避免产生冲突,我们应该将原始的 james.jar 文件放到一个安全的地方,并将我们的文件命名为 james-plus.jar。 为了加入我们自己的 mailet,需要编辑配置文件 config.xml ,它在 SAR-INF 目录下。我们要在配置文件中加两种标签。第一组标签仅仅是告诉James在那个包内查找匹配器类和mailet类。我们可以参考配置文件中对 org.apache 类的定义来定义我们的mailet包和匹配器包的标签。列表8说明了我们添加的标签。 列表8. 匹配器 和 mailet 包的声明 org.apache.james.transport.mailets com.claudeduguay.mailets org.apache.james.transport.matchers com.claudeduguay.mailets 在类的packages定义后,我们能够对应用程序进行配置,让它能够找到匹配器和mailet , 如列表9所示: 列表9. 匹配器 和 mailet 处理的声明 d:/james/james-2.1.2/unavailable You have been marked as UNAVAILABLE Send a message to available@localhost to reset. d:/james/james-2.1.2/unavailable You have been marked as AVAILABLE Send a message to unavailable@localhost to send the message to users when you are unavailable. d:/james/james-2.1.2/unavailable available@localhost;unavailable@localhost 如果你从来没有用过Ant,那么你会觉得列表10中的构建脚本很陌生。Ant是一个构建工具,它也来自 Apache 组织,现在广泛用于自动构建。我们将用这个工具自动解压原始的SAR文件、编译、重构、部署我们的应用程序。如果你不熟悉 Ant, 那你只能自己去了解它了。它不仅功能强大而且完全可移植,是自动构建领域的一个巨大飞跃。通过定制这个构建文件,你可以改变属性标签中说明的目录。 (资源部分有关于Ant的更多信息。) 列表10. Ant build 脚本 Project dir: ${project.dir} James dir: ${james.dir} JavaMail dir: ${javamail.dir} JAF dir: ${jaf.dir} Compiling Compiled Packaging Packaged 一旦完成构建工作,我们就可以用james/bin目录下的运行脚本启动James 服务器。如果一切运转正常,你会看到和第一篇中给出的一样的输出,表明James启动并开始运转。 在我们进行测试之前,需要设定 red、 green、 blue 三个用户。如果你还没有设定,可以按照第一篇文章中的指示去做。 模拟用户 一旦我们所有的代码都运行在服务器上之后,我们需要进行一组测试来证明我们的应用程序运转正常。 列表11中所示的JamesApplicationTest 类,集成了第一篇文章中开发的 JamesConfigTest 类,用我们开发的 MailClient 类来发送和读取e-mail。 我们如何测试我们的匹配器和 mailet 呢? 首先,我们清除 red、green,和blue用户的所有消息。然后我们分别从red和green用户发送邮件到blue,接下来让blue用户发送不可到达消息。在blue用户下次检查消息的时候,他应该能看到red和green用户最初发送的消息,还有unavailable用户发送的确认消息。这表明他的邮件被正确的保存下来了,而且他已经处于不可到达状态。blue用户还能继续进行正常的操作,发送和接收邮件。但其他任何用户在这种状态下给blue发送邮件时都会收到blue预存的不可到达消息。 通过给blue发送新的消息我们能够测试出用户处于不可到达状态时会发生什么事情。我们用green用户做这件事情,然后去检查green的收件箱。green用户会收到来自blue的一个不可到达消息,这个消息的内容就是blue发送到unavailable地址存储起来的消息。最后,blue发送一个可以到达消息并且检查是否有available地址发送过来的确认消息。 列表11. JamesApplicationTest: Putting our matchers and mailets through the paces public class JamesApplicationTest { public static void main(String[] args) throws Exception { // CREATE CLIENT INSTANCES MailClient redClient = new MailClient("red", "localhost"); MailClient greenClient = new MailClient("green", "localhost"); MailClient blueClient = new MailClient("blue", "localhost"); // CLEAR EVERYBODY'S INBOX redClient.checkInbox(MailClient.CLEAR_MESSAGES); greenClient.checkInbox(MailClient.CLEAR_MESSAGES); blueClient.checkInbox(MailClient.CLEAR_MESSAGES); Thread.sleep(500); // Let the server catch up // SEND A COUPLE OF MESSAGES TO BLUE (FROM RED AND GREEN) redClient.sendMessage( "blue@localhost", "Testing blue from red", "This is a test message"); greenClient.sendMessage( "blue@localhost", "Testing blue from green", "This is a test message"); // BLUE SENDS UNAVAILABLE MESSAGE blueClient.sendMessage( "unavailable@localhost", "On Vacation", "I am on vacation at the moment. " "I will answer your mail as soon as I get back."); Thread.sleep(500); // Let the server catch up // LIST BLUE MESSAGES (RED, GREEN & UNAVAILABLE CONFIRMATION) blueClient.checkInbox(MailClient.SHOW_AND_CLEAR); // GREEN SENDS A NORMAL MESSAGE TO BLUE greenClient.sendMessage( "blue@localhost", "Testing blue from green", "This is a test message"); Thread.sleep(500); // Let the server catch up // GREEN CHECKS MESSAGES (SHOULD SEE BLUE UNAVAILABLE MESSAGES) greenClient.checkInbox(MailClient.SHOW_AND_CLEAR); // BLUE SENDS MESSAGES TO BECOME AVAILABLE blueClient.sendMessage( "available@localhost", "Ignored subject", "Ignored content"); Thread.sleep(500); // Let the server catch up // BLUE CHECKS MAIL, SHOULD SEE MESSAGE FROM GREEN AND AVAILABLE MSG blueClient.checkInbox(MailClient.SHOW_AND_CLEAR); } } JamesApplicationTest 的输出应该如下所示: 列表12. JamesApplicationTest 输出 Clear INBOX for red@localhost Clear INBOX for green@localhost Clear INBOX for blue@localhost SENDING message from red@localhost to blue@localhost SENDING message from green@localhost to blue@localhost SENDING message from blue@localhost to unavailable@localhost Show and Clear INBOX for blue@localhost From: green@localhost Subject: Testing blue from green Content: This is a test message From: red@localhost Subject: Testing blue from red Content: This is a test message SENDING message from green@localhost to blue@localhost Show and Clear INBOX for green@localhost From: blue@localhost Subject: On Vacation Content: I am on vacation at the moment. I will answer your mail as soon as I get back. SENDING message from blue@localhost to available@localhost Show and Clear INBOX for blue@localhost From: available@localhost Subject: You have been marked as AVAILABLE Content: Send a message to unavailable@localhost to send the message to users when you are unavailable. From: green@localhost Subject: Testing blue from green Content: This is a test message From: unavailable@localhost Subject: You have been marked as UNAVAILABLE Content: Send a message to available@localhost to reset. 总结 从这篇文章中的代码可以看出,对James进行二次开发是很简单的。目前唯一复杂的处理就是部署的过程,这也是James开发小组现在正在进行改善的地方。既然e-mail是Internet上最广泛的应用,而且很明显它比Web服务更流行,那么思考可以由James基础设施取得的可能性就显的非常有趣了。这必将朝着解决重要问题的方向发展,而且所受到的唯一限制就是你的想像空间。 资源 下载这篇文章中的源代码。 在Apache James主页上下载James包。 到 Avalon 项目主页上学习Avalon 要运行这篇文章中的示例,你需要下载 JavaMail API 和 JavaBeans Activation Framework. 利用教程"Fundamentals of JavaMail API"学习JavaMail (developerWorks, August 2001). 深入了解Apache Ant 构建工具.
基于ApacheJames邮件服务器的收发邮件代码及服务 基于ApacheJames邮件服务器的收发邮件代码及服务,邮件服务器,简单的环境,发邮件,收邮件的类,直接运行即可! 立即下载

相关推荐

apache James使用入门

apache James使用入门,有apache小组开发的开源邮件服务器的使用入门

james源码重新打包部署公网邮件服务器

james源码重新打包部署公网邮件服务器前言准备工作apache jamesscala2.13java11mysqljava11的环境变量、maven的环境变量开始处理 前言 需求:希望在qq、163、腾讯企业邮箱收到邮箱时能够提示到我的一个小应用上 目前的能想到的实现方案包括: 定时扫描这三个邮件服务器看有没有收到邮件(可能会被封?如果太频繁了??) 自己建一个邮件服务器,然后比如qq收到后转发到我自己的邮件服务器,我自己的邮件服务器在给我的小应用推下消息 目前我这边采用的是第二种方式进行处理,虽然很麻

Qinejie1314520的博客 3848

apache-james-imap-api-0.3.jar

jar包,亲测可用

ApacheJames 介绍(转)

这篇文章是介绍ApacheJames邮件企业服务器的第一部分,也是James的介绍知识。它介绍了使用James开发服务端邮件程序的基础知识。它概括的介绍了Apache组织设计James目标以及如何安装配置一个可以运行的工作环境。你还可以了解到ApacheJames都提供哪些功能。你还将看到James提供匹配器(matcher)和mailet实现的有关描述,以及它与创通邮件服务器的不同。Java A

sybww的专栏 1933

apache-james-mailbox-api-0.2.jar

jar包,亲测可用

基于物联网技术智慧园林绿化养护管理信息平台

近几年来,随着经济不断的发展,城市面积不断的扩大,城市管理中的园林绿化工作也在这种趋势下不断的发生着深刻改变。管养企业是否按制定的管养计划严格执行?绿化事件整改是否及时到位?绿地面积是否在稳步增长?管养的效果如何?如何客观评价管养企业的管养工作?这些都是我们各级管理者需要面对的问题。   智慧园林绿化养护管理信息平台的开发思路以“考核”为核心,整个信息平台体现出“新、快、高、全、享”五个特点。   智慧园林绿化养护管理信息平台的整个开发理念为:依托五大技术手段(全球卫星定位系统技术、地理信...

Cesium的博客QQ2252224326 2460

JAMES 垃圾邮件过滤

最近公司发布了一个JAMES邮件服务器, 第二天早一来, 发现spool里面有几万的垃圾邮件. 在网上仔细查了一下, 一般都是自定义一个matcher和一个mailet, 如: package com.easynet.mailet; import java.util.Collection; import java.util.Iterator; import java.util.Vector; i...

心雨楼 644

WeDetect:基于视觉-语言检索的目标检测新范式

目标检测正从传统回归与分类耦合范式,向开放、灵活、可扩展的多模态检索范式演进。检索式检测(Retrieval-based Detection)将检测任务重构为视觉特征与文本语义的联合匹配过程,依托候选框索引库与双塔架构,天然支持开放词汇、零样本识别与小目标定位。其技术价值在于解耦空间感知与语义理解,消除NMS与anchor匹配等冗余计算,显著提升推理效率与跨场景泛化能力。典型应用场景包括工业质检中的缺陷新增识别、遥感图像小目标检测、低光照鲁棒视觉系统等。WeDetect正是这一范式的代表性实现,深度融合视觉

weixin_30878501的博客 363

用JAMES实现自己的邮件服务器 (一)

 http://james.apache.org/download.cgi  现在让我们开始我们激动人心的james之旅。首先我们将james-binary-2.3.1.zip解压缩下载到你的安装目录。我们可以把这个过程理解为安装的过程。我在这里将它解压到c:/.并且把它改名为james.这样我们的james就安装好了。目录为C:/james。很简单吧! pig@sina.co

恶人 1163

Vivado 2018.3 SDK烧写bin文件避坑指南:如何解决QSPI模式下的常见错误

本文深入解析了在Vivado 2018.3 SDK中为Zynq FPGA烧写QSPI Flash时遇到的常见问题,特别是启动模式为QSPI时出现的警告与失败。文章从Zynq启动机制入手,提供了修改FSBL代码以强制使用JTAG模式、调整硬件配置等核心解决方案,并分享了实战案例与最佳实践,帮助开发者高效避坑,确保bin文件烧写成功。

arduino9maker的博客 390

Oracle-OGG trail 文件大小引起的进程异常 OGG-01172

监控OGG目标端进程,其中一个进程异常,状态为 ABENDED,start repa 执行失败。进入OGG报告目录检查运行报告 2015-04-20 09:38:36 ERROR OGG-01172 Discard file (/ogg/oggrm/11.2/dirdat/repa.dsc) exceeded max bytes (2000000000). 总结处理方法,从根本上解决问题。

xdyzgjy的专栏 7957

apache james_Apache的James企业电子邮件服务器简介

Java Apache Mail Enterprise Server(通常称为James )是由Apache组构建的便携式,安全且100%纯Java企业邮件服务器。 但是,由于其可插拔的协议体系结构和可用于电子邮件的servlet基础结构,它的潜力远不止于此 ,servlet可以为Web服务器提供服务。 自DARPA投入资金以来,电子邮件服务器一直存在,直到最终成为Internet,但Jame...

cusi77914的博客 2596

接地设计的本质:按电流类型选择物理连接方式

接地是电子系统中实现电位参考、噪声抑制与安全保护的基础技术,其核心原理在于为不同性质的电流提供可控的低阻抗返回路径。从直流到GHz频段,电流的频率特性、能量等级和持续时间决定了接地的物理实现方式——工频安全电流依赖低电阻导体,高频噪声需低感平面或磁珠衰减,ESD脉冲要求受控泄放电阻,浪涌能量则必须通过独立短路径导入大地。这种‘目的决定方式’的设计逻辑,直接关联EMC合规性、信号完整性与系统可靠性。本文聚焦PCB级与设备级工程实践,详解安全地、功能地、浪涌地与静电地的判据差异及六种典型连接策略,帮助硬件工程师

weixin_36369848的博客 261

James 3.0 邮箱配置

默认使用文件存储信息,如果用mysql,只需修改conf/james-database.properties即可: database.driverClassName=com.mysql.jdbc.Driver database.url=jdbc:mysql://localhost:3306/mail?autoReconnect=true&zeroDateTimeBehavior=convertT

after_的专栏 5580

CPU设计实战:Loongarch版 lab6--20条指令单周期CPU

这个debug卡我时间最长的就是通用寄存器的写使能信号,当时一直没找到,甚至把golden—trace生成了一遍又一遍,对照test,检查了各种,卡了很长时间,我都以为是我之前哪一步搞错了,或者环境什么的,但是一步步做下来并没有,并且“机器永远是对的”让我终于查到了错。debug到一半才想起来写个博客,就不写过程了,下个lab再写过程。下面是两个模块的代码,运行已通过仿真验证。其他的bug就还好,如果认真跟着。就能马上找出来,,上面的每一句话都很重要。走,按逻辑检查并且查。

m0_65369544的博客 6305

STM32CubeIDE入坑指南

一 前言 在科技日新月异的今天,作为从事效率为先的苦逼 IT 行业,秉承着我不入地狱谁入地狱的伟大革命精神,我决定再一次做第一个吃螃蟹的人,通过自身的入坑过程,为大家测试STM32CubeIDE这款新式工具。(其实是为了我能省点时间,快点做完项目,多挣点钱买几瓶肾气丸) 二 看一看别人是如何入坑的 二 手把手带你入坑 三 相关资料 ...

CH的博客 1万+

James之——添加自定义处理过程

//————————————————————修改记录:2018.06.25 初次发布//————————————————————注:文中James是基于2.3.2开发的Why?    James提供了信件的收发功能,但是没有提供收发记录的存储,这样不利于对信件和数据的流向进行跟踪,存在风险。    本文将介绍如何通过添加自定义的处理过程,将James收发信件的记录都存储到一张数据库表中(关于数据量...

~_~的博客 857

如何通过 Python 爬虫抓取并分析政府开放数据

通过本文的介绍,我们展示了如何使用Python 爬虫抓取并分析政府开放数据。通过requests获取政府开放数据的 API 接口数据。使用和pandas进行数据清洗与存储。使用matplotlib对数据进行可视化。你可以根据不同的政府开放平台和数据集进行调整,应用于不同领域的数据分析,如公共健康、交通、环保等。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1079

James3之——安装与配置

Why? James-3.1.0 较于 2.3 功能更加完善,详情参见官网: https://github.com/apache/james-project/#apache-james-project 拥抱Docker,可以将数据卷挂载到Host上,还可集成ElasticSearch或Lucene(基于Guice): https://github.com/apache/james-proj...

~_~的博客 9784

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

企业级邮件服务器Apache James介绍(1)

英文原文:http://www-106.ibm.com/developerworks/java/library/j-james1.html学习这个开源项目的基础知识级别: 中级Claude Duguay (claude.duguay@verizon.net)首席架构师, Arcessa, Inc.6,10, 2003Java Apache企业级邮件服务器 -- 通常被称为James --是Apac

恶人 1253

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

邮件服务器James搭建企业邮件系统

中小企业是否可以免费拥有自己的邮件系统,而不是去购买腾讯,163的企业邮箱。答案是肯定的,可以,Java开源的邮件系统很多,经过筛选,调研最终我们选择用James来搭建自己的邮件系统。接下来我们来看看window7环境下如何用James来搭建邮件系统: Apache James 简称 James, 是 Java Apache Mail Enterprise Server的缩写。James 是10

夏风 2万+

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

James使用Mailet接收外网邮件通知提醒

即他们都有 类似的生命周期,Mailet的简单可编程接口可以用来做一些邮件处理,比如反垃圾邮件,检查邮件病毒以及邮件博客等等,利用移动设备可发送email的功能,可以做到手机通过mail发送信息到邮件服务器交给Mailet处理,形成移动博客的模型。Mailet的运行需要mailet-2.3.jar和mailet-api-2.3.jar两个包的支持,James本身就有这两个包,可不作修改,但在开发的时候还是需要开发者自己将这两个包导入到工程的Build path中或配置到系统环境变量中。

涛哥是个大帅比 1706

开源邮件服务器James 3.5.x 二次开发将邮件内容推送到kafka 源码、可执行程序、部署过程分享

部署james服务、修改配置、创建初始用户

jinghuay的博客 1357

James改造

版本:apache-james-2.3.2 改为明文验证 参考:http://blog.sina.com.cn/s/blog_55317f42010091u1.html 修改org.apache.james.userrepository.DefaultUser verifyPassword方法改为: public boolean verifyPassword(String pass) {

weisuochengxuyuan的专栏 1373

Apache James用户信息的数据库存储和密码问题

本文主要解决两个问题:一个是如何将James的用户信息存储到数据库中,二是在进行James二次开发时,如何处理密码问题。本文面向对James有一定使用经验的用户,对于James的初学者,请先阅读我的另一篇文章《Apache Ja...

cqwf95925的博客 548

用JAMES实现自己的邮件服务器

简介 James 是一个企业级的邮件服务器,它完全实现了smtp 和 pops 以及nntp 协议。同时,james服务器又是一个邮件应用程序平台。James的核心是Mailet API,而james 服务齐是一个mailet的容器。它可以让你非常容易的实现出很强大的邮件应用程序。James开源项目被广泛的应用于与邮件有关的项目中。你可以通过它来搭建自己的邮件服务器。我们可以利用Mail

songwenbinasdf的专栏 1642
上一篇: java编程规则(摘自《think in java》)
下一篇: 用Java实现FTP服务器
java169
博客等级 码龄19年 27粉丝 2568原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值