首先要安裝 James Server 3.0
可以參考 Quick Start
1: 先確認系統環境,必須有安裝JDK 1.5+
2: 下載james-server-container-spring-3.0-M2-bin.zip ,並解壓到指定資料夾(EX c:\)
然後要做一些設定,James 3.0 版本在設定上分成多個XML
相關XML的細節可參考 Configure James Server , 這邊只針對幾個設定做說明
打開cmd 輸入ipconfig /all , 查看local 的DNS設定
打開{yourJamesServerPath}\conf\dnsservice.xml ,設定如下
dnsservice.xml 相關的設定如下:
<!-- DNS Service Block --> <!-- --> <!-- Specifies DNS Server information for use by various components inside --> <!-- James. --> <!-- --> <!-- If autodiscover is true, James will attempt to autodiscover the DNS servers configured on your underlying system.--> <!-- Currently, this works if the OS has a unix-like /etc/resolv.conf,--> <!-- or the system is Windows based with ipconfig or winipcfg.--> <!-- --> <!-- If no DNS servers are found and you have not specified any below, 127.0.0.1 will be used--> <!-- If you use autodiscover and add DNS servers manually a combination of all the dns servers will be used --> <!-- --> <!-- Information includes a list of DNS Servers to be used by James. These are --> <!-- specified by the server elements, each of which is a child element of the --> <!-- servers element. Each server element is the IP address of a single DNS server. --> <!-- The servers element can have multiple server children. --> <dnsservice> <servers> <!--Enter ip address of your DNS server, one IP address per server --> <!-- element. --> <!-- <server>127.0.0.1</server> --> </servers> <!-- Change autodiscover to false if you would like to turn off autodiscovery --> <!-- and set the DNS servers manually in the <servers> section --> <autodiscover>true</autodiscover> <authoritative>false</authoritative> <!-- Maximum number of entries to maintain in the DNS cache --> <maxcachesize>50000</maxcachesize> <!-- Uncomment this if you want James to try a single server for each --> <!-- multihomed mx host. --> <!-- <singleIPperMX> true </singleIPperMX> --> </dnsservice>
打開{yourJamesServerPath}\conf\domainlist.xml, 設定如下,這邊主要設定dns namespace identifies
以下是domainlist.xml的說明
<!-- Domainnames identifies the DNS namespace served by this instance of James. --> <!-- These domainnames are used for both matcher/mailet processing and SMTP auth --> <!-- to determine when a mail is intended for local delivery. --> <!-- --> <!-- If autodetect is TRUE, James wil attempt to discover its own host name AND --> <!-- use any explicitly specified servernames. --> <!-- If autodetect is FALSE, James will use only the specified domainnames. --> <!-- --> <!-- If autodetectIP is not FALSE, James will also allow add the IP address for each servername. --> <!-- The automatic IP detection is to support RFC 2821, Sec 4.1.3, address literals. --> <!-- --> <!-- To override autodetected domainames names simply add explicit domainname elements. --> <!-- In most cases this will be necessary. --> <!-- By default, the domainname 'localhost' is specified. This can be removed, if required. --> <!-- --> <!-- Warning: If you are using fetchmail it is important to include the --> <!-- fetched domains in the server name list to prevent looping. --> <domainlists> <!-- XML based DomainList implementation --> <domainlist class="org.apache.james.domainlist.xml.XMLDomainList"> <domainnames> <domainname>localhost</domainname> </domainnames> <autodetect>true</autodetect> <autodetectIP>true</autodetectIP> </domainlist> <!-- JPA implementation for DomainList --> <!-- <domainlist class="org.apache.james.domainlist.jpa.JPADomainList"> <autodetect>true</autodetect> <autodetectIP>true</autodetectIP> </domainlist> --> <!-- JDBC implementation for DomainList. This is deprecated and should not be used. --> <!-- Use JPADomainList if you need a db backend DomainList --> <!-- <domainlist class="org.apache.james.domainlist.jdbc.JDBCDomainList"> <repositoryPath>db://maildb/domain</repositoryPath> <sqlFile>file://conf/sqlResources.xml</sqlFile> <autodetect>true</autodetect> <autodetectIP>true</autodetectIP> </domainlist> --> </domainlists>
修改C:\WINDOWS\system32\drivers\etc\hosts , 增加domain & ip mapping
打開{yourJamesServerPath}\conf\mailserver.xml, 設定如下
defaultDomain 為預設的domain name, 設成mydomain.james
postmaster設為Postmaster@mydomain.james , 如果新增一個user 叫AAA ,那mail位置就為AAA@mydomain.james
mailserver.xml的相關設定說明
<mailserver> <!-- CHECKME! --> <!-- This is the postmaster email address for this mail server. --> <!-- Set this to the appropriate email address for error reports --> <!-- If this is set to a non-local email address, the mail server --> <!-- will still function, but will generate a warning on startup. --> <postmaster>Postmaster@localhost</postmaster> <!-- Set to true to support virtualHosting. If virtualHosting support is enabled the server will accept thread every user independ on --> <!-- domain level. --> <enableVirtualHosting> false </enableVirtualHosting> <!-- Set the default domain which will be used if an email is send to a recipient without a domain part --> <!-- If not defaultdomain is set the first domain of the DomainList get used --> <defaultDomain> localhost </defaultDomain> <!-- This is the name used by the server to identify itself in the RemoteManager --> <!-- protocol. If autodetect is TRUE, the server will discover its --> <!-- own host name and use that in the protocol. If discovery fails, --> <!-- the value of 'localhost' is used. If autodetect is FALSE, James --> <!-- will use the specified value. --> <!-- Set the default helloName which is used in all services if not overridden in the specific service--> <helloName autodetect="true">myMailServer</helloName> </mailserver>
然後在cmd 下進入{yourJamesServerPath}\bin, 輸入james install, 安裝james
再輸入james start , 會啟動james server,如下圖所示:
然後輸入telnet mydomain.james 4555 ,連進admin設定, 預設的acct/passwd 都是root
進入後可以新增user , 使用adduser [acctname] [passwd] , 新增一個test , 位置就是test@mydomain.james
然後可以telnet 到mydomain.james 25 做動作,但這邊我用outlook 收發mail
設定如下,
就能正常的收發信了(外信如gmail要發到內部domain這邊不在處理範圍內:p )
再來就是主要的Mailet & Matcher , Mailet API是一個用來做郵件處理程序的簡單的API。 James是Mailet的容器,通過Mailet(定制的或已有的)完成各種複雜的郵件處理任務,類似Servlet ,
這邊用Maven Create 一個sample Maven Project , pom.xml如下
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.my.james</groupId> <artifactId>MyJames.Mailet</artifactId> <version>1.0.0</version> <dependencies> <dependency> <groupId>james</groupId> <artifactId>james</artifactId> <version>3.0a1</version> </dependency> <dependency> <groupId>org.apache.james</groupId> <artifactId>apache-mailet-base</artifactId> <version>1.1</version> </dependency> <dependency> <groupId>james</groupId> <artifactId>mailet-api</artifactId> <version>3.0</version> </dependency> <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.4.1</version> </dependency> </dependencies> </project>
Mailet 的部份
com.mypackage.mailets.FilterByMailet
package com.mypackage.mailets; import java.io.IOException; import java.util.Collection; import java.util.Iterator; import javax.mail.BodyPart; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; import org.apache.mailet.Mail; import org.apache.mailet.MailAddress; import org.apache.mailet.base.GenericMailet; /** * @author momo * */ public class FilterByMailet extends GenericMailet { @Override public void init(){ this.log("===> test for FilterByMailet init()"); System.out.println("===> test for FilterByMailet init()"); } public void service(Mail mail) throws MessagingException { this.log(""); try { this.log("====> MailetInfo =" this.getMailetInfo()); System.out.println("====> MailetInfo =" this.getMailetInfo()); // TODO Auto-generated method stub this.log("====> sender = " mail.getSender().toString()); Collection c = mail.getRecipients(); Iterator it = c.iterator(); if (it.hasNext()) { MailAddress recipient = (MailAddress) it.next(); this.log("====> recipient = " recipient.toString()); } MimeMessage msg = mail.getMessage(); this.log("====> subject = " msg.getSubject()); this.log("====> contentType = " msg.getContentType()); if (msg.getContent() instanceof MimeMultipart) { MimeMultipart content = (MimeMultipart) msg.getContent(); for (int i = 0; i < content.getCount(); i ) { BodyPart p = content.getBodyPart(i); this.log(i ".n" p.getContentType() "n" p.getContent()); } } } catch (IOException e) { this.log(e.getMessage()); } catch (MessagingException e) { this.log(e.getMessage()); } } }
init()可有,可沒有, service() 為必須的, 透過Matcher return collection 後會進入mailet service(), 如果Matcher沒有轉給其他的processor的話,
然後是Matcher的部份,這邊實作的是GenericMatcher , 有另一個為GenericRecipientMatcher ,
GenericMatcher return 為null or mail.getRecipients(), mail.getRecipients()為一個Collection
com.mypackage.matcher.MatcherBySubject
/** * */ package com.mypackage.matcher; import java.util.Collection; import javax.mail.MessagingException; import org.apache.mailet.Mail; import org.apache.mailet.MailAddress; import org.apache.mailet.base.GenericMatcher; import org.apache.mailet.base.GenericRecipientMatcher; /** * @author momo * */ public class MatcherBySubject extends GenericMatcher { @Override public Collection match(Mail mail) throws MessagingException { this.log("-->MatcherBySubject start "); System.out.println("MatcherBySubject return -true"); this.log("getSender =" mail.getSender()); System.out.println("getSender =" mail.getSender()); return null; } }
然後打開{yourJamesServerPath}\conf\mailetcontainer.xml, 設定如下
這邊要注意一點,自訂的mailet & matcher設定如下
<mailet match="MatcherBySubject" class="com.mypackage.mailets.FilterByMailet"/>
以上的設定要在 RecipientIsLocal , 這個matcher 的前面,
<mailet match="HostIsLocal" class="ToProcessor"> <processor>local-address-error</processor> <notice>550 - Requested action not taken: no such user here</notice> </mailet>
主要是因為Mailet 透過SpoolManager 來控制, SpoolManager 針對processor children 為樹狀模式, 每個processor 都有一個唯一的name屬性, 主要的processor為必要的(如root, error), 而"ghost" 是不可使用的,ghost用來表示不再接受更進一步處理的訊息。James的SpoolManager在processor的名稱和郵件“state”之間創建對應關係。如果狀態改變了,那這個消息就不會繼續留在當前的處理器中。如果為ghost對這個的處理就中止,相對的matcher也可以設定state轉發到另一個processor 。 HostIsLocal的內容如下:
/** * This mailet redirects the mail to the named processor * * Sample configuration: * <mailet match="All" class="ToProcessor"> * <processor>spam</processor> * <notice>Notice attached to the message (optional)</notice> * </mailet> * */ public class ToProcessor extends GenericMailet { /** * Controls certain log messages */ private boolean isDebug = false; /** * The name of the processor to which this mailet forwards mail */ String processor; /** * The error message to attach to the forwarded message */ String noticeText = null; /** * Initialize the mailet * * @throws MailetException if the processor parameter is missing */ public void init() throws MailetException { isDebug = (getInitParameter("debug") == null) ? false : new Boolean(getInitParameter("debug")).booleanValue(); processor = getInitParameter("processor"); if (processor == null) { throw new MailetException("processor parameter is required"); } noticeText = getInitParameter("notice"); } /** * Deliver a mail to the processor. * * @param mail the mail to process * * @throws MessagingException in all cases */ public void service(Mail mail) throws MessagingException { if (isDebug) { StringBuffer logBuffer = new StringBuffer(128).append( "Sending mail ").append(mail).append(" to ") .append(processor); log(logBuffer.toString()); } mail.setState(processor); if (noticeText != null) { if (mail.getErrorMessage() == null) { mail.setErrorMessage(noticeText); } else { StringBuffer errorMessageBuffer = new StringBuffer(256) .append(mail.getErrorMessage()).append("\r\n") .append(noticeText); mail.setErrorMessage(errorMessageBuffer.toString()); } } } /** * Return a string describing this mailet. * * @return a string describing this mailet */ public String getMailetInfo() { return "ToProcessor Mailet"; } }
因為這邊會對自己發信,matcher會match到為local 所以會進入ToProcessor mailet, 在這邊processor = getInitParameter("processor");會設定為local-address-error , 進入service時mail.setState(processor);,這邊就會轉發給local-address-error , 所以我們自訂Mailet 時要注意mailet的位置。
update:
修改Default database from DERBY to MYSQL ,需要mysql-connector-java-5.1.15.jar , 將其放到{yourJamesPath}\conf\lib 下面 ,打開{yourJamesServerPath}\conf\database.properties, 設定如下
然後重啟james server , telnet myhdomain.james 4555 , 重新新增user , James Server 會對db 做create table 的動作。 每一封信寄到James Server時會insert 到database , 當使用者用tools收信時會清除資料。
Update 05/24:
修改smtpserver.xml , 可以透過增加 authorizedAddresses ,讓來源IP 能不需要認證使用mail relay的功能, 新增一個192.168.2.168
<!-- See http://james.apache.org/server/3/config.html for usage --> <smtpserver enabled="true"> <port>25</port> <connectionBacklog>200</connectionBacklog> <tls socketTLS="false" startTLS="false"> </tls> <handler> <connectiontimeout>360</connectiontimeout> <connectionLimit> 0 </connectionLimit> <connectionLimitPerIP> 0 </connectionLimitPerIP> <authorizedAddresses>127.0.0.0/8,192.168.2.168</authorizedAddresses> <authRequired>true</authRequired> <maxmessagesize>0</maxmessagesize> <addressBracketsEnforcement>true</addressBracketsEnforcement> <handlerchain> <handler class="org.apache.james.smtpserver.fastfail.ValidRcptHandler"/> <handler class="org.apache.james.smtpserver.CoreCmdHandlerLoader"/> </handlerchain> </handler> </smtpserver>
Reference:
Mailet API Overview
Mailet Container Configuration
Mailets and Matchers Reference
Working with James, Part 1: An introduction to Apache's James enterprise e-mail server
James - Mailet Sample - Omikuji
請問一下~ 關於設定server的部分
回覆刪除為什麼我的{yourJamesServerPath}\conf\裡面沒有mailserver.xml檔呢 !!?
我比對了一下這編在測試用的版本james-server-container-spring-3.0-M2 跟官網現在3.0 的beta版本apache-james-3.0-beta3-app, 新的版本確實是沒有mailserver.xml ,但是在quicstart裡面又有提到mailserver.xml 的檔案(http://james.apache.org/server/3/quick-start.html , 看Step 4: Configure ) 你可以試試看自己建一個mailserver.xml 放上去...@@
回覆刪除我會試試滴~ 謝謝你 ^^
回覆刪除我有測了一下,mailserver.xml 不放的話 照著quick-start 的去啟動,是可以正常啟動mailserver的,可能新版的設定跟我之前用的m2版有些差別吧
回覆刪除再次感謝 >//<
回覆刪除不好意思~ 再請問一下
回覆刪除為什麼我打telnet mydomain.james 4555時會出現下面這種訊息呢?
'telnet' is not recognized as an internal or external command,
operable program or batch file.
我該在哪個目錄下面打這行指令呢?
不好意思~ 我知道囉!! 是win 7把功能鎖調而已 XD
回覆刪除啊,我上週回是用gmail直接回信...忘了他是noreplay的Orz...
回覆刪除不過你有解掉就好了^^
天啊!! 怎麼一直碰到問題..好笨阿我 @@
回覆刪除為什麼我打telnet mydomain.james 4555後會出現下面的錯誤訊息 :
Connecting To mydomain.james...Could not open connection to the host, on port 45
55: Connect failed
這應該是james啟動的時候不認得mydomain.james , 你可以試著用localhost or 127.0.0.1 看行不行, 或著啟動james server後先連看看telnet 127.0.0.1 25試試james server正常啟動了嗎, 新的3.0 beta 的設定還沒去研究過,照我上面的設定應該admin 連的時候會有問題
回覆刪除終於OK囉!!!! 結果我又灌回2.3.2版~ 那個問題就沒有了 ^^
回覆刪除3.0 beta的話還在開發,建議可以等release再用, 不然就要去apache project fourm看討論或問題了, 因為他每次進版會少或多了什麼設定檔也不一定...
回覆刪除如果只是要用mail server的話2.3.x其實還算可用..
只是功能太少,太舊 ..XD
@@ ~~~
回覆刪除Sorry , I didn't update blog for a long time. XDDD