org.apache.james.JamesMailServer Maven / Gradle / Ivy
/****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one *
* or more contributor license agreements. See the NOTICE file *
* distributed with this work for additional information *
* regarding copyright ownership. The ASF licenses this file *
* to you under the Apache License, Version 2.0 (the *
* "License"); you may not use this file except in compliance *
* with the License. You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, *
* software distributed under the License is distributed on an *
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
* KIND, either express or implied. See the License for the *
* specific language governing permissions and limitations *
* under the License. *
****************************************************************/
package org.apache.james;
import java.net.UnknownHostException;
import java.util.Locale;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.mail.internet.ParseException;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.apache.commons.logging.Log;
import org.apache.james.dnsservice.api.DNSService;
import org.apache.james.domainlist.api.DomainList;
import org.apache.james.lifecycle.Configurable;
import org.apache.james.lifecycle.LogEnabled;
import org.apache.james.services.MailServer;
import org.apache.mailet.MailAddress;
/**
*
*/
public class JamesMailServer
implements MailServer, LogEnabled, Configurable {
/**
* The software name and version
*/
private final static String SOFTWARE_NAME_VERSION = Constants.SOFTWARE_NAME + " " + Constants.SOFTWARE_VERSION;
/**
* The top level configuration object for this server.
*/
private HierarchicalConfiguration conf = null;
/**
* The number of mails generated. Access needs to be synchronized for
* thread safety and to ensure that all threads see the latest value.
*/
private static int count = 0;
private static final Object countLock = new Object();
private DomainList domains;
private boolean virtualHosting = false;
private String defaultDomain = null;
private String helloName = null;
private Log logger;
private DNSService dns;
private MailAddress postmaster;
@Resource(name="domainlist")
public void setDomainList(DomainList domains) {
this.domains = domains;
}
@Resource(name="dnsservice")
public void setDNSService(DNSService dns) {
this.dns = dns;
}
/*
* (non-Javadoc)
* @see org.apache.james.lifecycle.LogEnabled#setLog(org.apache.commons.logging.Log)
*/
public final void setLog(Log logger) {
this.logger = logger;
}
/*
* (non-Javadoc)
* @see org.apache.james.lifecycle.Configurable#configure(org.apache.commons.configuration.HierarchicalConfiguration)
*/
public void configure(HierarchicalConfiguration config) throws ConfigurationException {
this.conf = (HierarchicalConfiguration)config;
}
@PostConstruct
public void init() throws Exception {
logger.info("JAMES init...");
if (conf.getKeys("usernames").hasNext()) {
throw new ConfigurationException(" parameter in James block was removed. Please configure this data in UsersRepository block");
}
if (conf.getKeys("servernames").hasNext()) {
throw new ConfigurationException(" parameter in mailserver block was removed. Please configure this data in domainlist block");
}
initializeServernames();
logger.info("Private Repository LocalInbox opened");
virtualHosting = conf.getBoolean("enableVirtualHosting", false);
logger.info("VirtualHosting supported: " + virtualHosting);
defaultDomain = conf.getString("defaultDomain",null);
if (defaultDomain == null && virtualHosting) {
throw new ConfigurationException("Please configure a defaultDomain if using VirtualHosting");
}
logger.info("Defaultdomain: " + defaultDomain);
if (conf.getKeys("helloName").hasNext()) {
HierarchicalConfiguration helloNameConfig = conf.configurationAt("helloName");
boolean autodetect = helloNameConfig.getBoolean("[@autodetect]", true);
if (autodetect) {
try {
helloName = dns.getHostName(dns.getLocalHost());
} catch (UnknownHostException e) {
helloName = "localhost";
}
} else {
// Should we use the defaultdomain here ?
helloName = conf.getString("helloName",defaultDomain);
}
}
initPostmaster();
System.out.println(SOFTWARE_NAME_VERSION);
logger.info("JAMES ...init end");
}
private void initializeServernames() throws ConfigurationException, ParseException {
String defaultDomain = getDefaultDomain();
if (domains.containsDomain(defaultDomain) == false) {
logger.warn("Configured defaultDomain not exist in DomainList, please add it ASAP!");
}
}
/**
* Note that this method ensures that James cannot be run in a distributed
* fashion.
* Two instances may return the same ID.
* There are various ways that this could be fixed.
* The most obvious would be to add a unique prefix.
* The best approach would be for each instance to be configured
* with a name which would then be combined with the network
* address (for example, [email protected]) to create a
* unique James instance identifier.
*
* Alternatively, using a data store backed identifier (for example, from a sequence
* when DB backed) should be enough to gaurantee uniqueness. This would imply
* that the Mail interface or the spool store should be responsible for creating
* new Mail implementations with ID preassigned.
*
* It would be useful for each
* James cluster to have a unique name. Perhaps a random number could be generated by
* the spool store upon first initialisation.
*
* This ID is most likely
* to be used as message ID so this is probably useful in any case.
*
*
* @see org.apache.james.services.MailServer#getId()
*/
public String getId() {
final long localCount;
synchronized (countLock) {
localCount = count++;
}
StringBuffer idBuffer =
new StringBuffer(64)
.append("Mail")
.append(System.currentTimeMillis())
.append("-")
.append(localCount);
return idBuffer.toString();
}
/**
* @see org.apache.james.services.MailServer#supportVirtualHosting()
*/
public boolean supportVirtualHosting() {
return virtualHosting;
}
/**
* @see org.apache.james.services.MailServer#getDefaultDomain()
*/
public String getDefaultDomain() {
if (defaultDomain == null) {
String[] domainList = domains.getDomains();
if (domainList == null || domainList.length < 1) {
return conf.getString("defaultDomain", "localhost");
} else {
return domainList[0];
}
} else {
return defaultDomain;
}
}
/**
* @see org.apache.james.services.MailServer#getHelloName()
*/
public String getHelloName() {
if (helloName != null) {
return helloName;
} else {
return getDefaultDomain();
}
}
private void initPostmaster() throws Exception {
// Get postmaster
String postMasterAddress = conf.getString("postmaster", "postmaster").toLowerCase(Locale.US);
// if there is no @domain part, then add the first one from the
// list of supported domains that isn't localhost. If that
// doesn't work, use the hostname, even if it is localhost.
if (postMasterAddress.indexOf('@') < 0) {
String domainName = null; // the domain to use
// loop through candidate domains until we find one or exhaust the
// list
String[] doms = domains.getDomains();
if (doms != null) {
for (int i = 0; i < doms.length; i++) {
String serverName = doms[i].toLowerCase(Locale.US);
if (!("localhost".equals(serverName))) {
domainName = serverName; // ok, not localhost, so use it
continue;
}
}
}
// if we found a suitable domain, use it. Otherwise fallback to the
// host name.
postMasterAddress = postMasterAddress + "@" + (domainName != null ? domainName : getDefaultDomain());
}
this.postmaster = new MailAddress(postMasterAddress);
if (!domains.containsDomain(postmaster.getDomain())) {
StringBuffer warnBuffer = new StringBuffer(320).append("The specified postmaster address ( ").append(postmaster).append(
" ) is not a local address. This is not necessarily a problem, but it does mean that emails addressed to the postmaster will be routed to another server. For some configurations this may cause problems.");
logger.warn(warnBuffer.toString());
}
}
/*
* (non-Javadoc)
* @see org.apache.james.services.MailServer#getPostmaster()
*/
public MailAddress getPostmaster() {
return postmaster;
}
}