package mireka.transmission.immediate.host;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import mireka.address.Recipient;
import mireka.smtp.EnhancedStatus;
import mireka.smtp.SendException;
import mireka.smtp.client.MtaAddress;
import mireka.smtp.client.SmtpClient;
import mireka.transmission.Mail;
import mireka.transmission.immediate.PostponeException;
import mireka.transmission.immediate.RecipientRejection;
import mireka.transmission.immediate.RecipientsWereRejectedException;
import mireka.transmission.immediate.RemoteMtaErrorResponseException;
import mireka.transmission.queuing.LogIdFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.subethamail.smtp.client.SMTPException;
import org.subethamail.smtp.client.SmartClient;
/**
* MailToHostTransmitter transmits a mail to a specific host specified by its IP
* address.
*/
public class MailToHostTransmitter {
private final Logger logger = LoggerFactory
.getLogger(MailToHostTransmitter.class);
private OutgoingConnectionsRegistry outgoingConnectionRegistry;
private LogIdFactory logIdFactory;
/**
* Delivers the mail to the SMTP server running on the specified host.
*
* @param client
* an unconnected, but otherwise fully initialized
* {@link SmtpClient}.
* @throws PostponeException
* if it has not even tried connecting to the host, because it
* is likely that the host is busy at this moment.
*/
public void transmit(Mail mail, SmtpClient client) throws SendException,
RecipientsWereRejectedException, PostponeException {
MtaAddress remoteMta = client.getMtaAddress();
try {
outgoingConnectionRegistry
.openConnection(client.getMtaAddress().address);
} catch (PostponeException e) {
e.setRemoteMta(remoteMta);
throw e;
}
try {
client.connect();
client.from(mail.from.getSmtpText());
List<RecipientRejection> recipientRejections =
new ArrayList<RecipientRejection>();
List<Recipient> acceptedRecipients = new ArrayList<Recipient>();
for (Recipient recipient : mail.recipients) {
try {
client.to(recipient.sourceRouteStripped());
acceptedRecipients.add(recipient);
} catch (SMTPException e) {
RemoteMtaErrorResponseException sendException =
new RemoteMtaErrorResponseException(e, remoteMta);
recipientRejections.add(new RecipientRejection(recipient,
sendException));
String logId = logIdFactory.next();
sendException.initLogId(logId);
logger.debug("Recipient " + recipient
+ " was rejected/failed. Log-ID=" + logId
+ ". Continuing with the next recipient if one "
+ "exists. " + e.getResponse());
}
}
if (acceptedRecipients.isEmpty()) {
logger.debug("All recipients were rejected");
throw new RecipientsWereRejectedException(recipientRejections);
}
client.dataStart();
writeMailConent(mail, client);
client.dataEnd();
if (!recipientRejections.isEmpty())
throw new RecipientsWereRejectedException(recipientRejections);
else
return;
} catch (SMTPException e) {
throw new RemoteMtaErrorResponseException(e, remoteMta);
} catch (UnknownHostException e) {
// impossible
throw new RuntimeException(e);
} catch (IOException e) {
throw new SendException("Connection failed: " + e.toString(), e,
new EnhancedStatus(450, "4.4.0",
"No answer from host or bad connection"));
} finally {
if (client != null) {
client.quit();
}
outgoingConnectionRegistry.releaseConnection(remoteMta.address);
}
}
private void writeMailConent(Mail mail, SmartClient smartClient)
throws IOException {
SmartClientOutputStreamAdapter out =
new SmartClientOutputStreamAdapter(smartClient);
mail.mailData.writeTo(out);
}
/**
* @x.category GETSET
*/
public void setOutgoingConnectionRegistry(
OutgoingConnectionsRegistry outgoingConnectionRegistry) {
this.outgoingConnectionRegistry = outgoingConnectionRegistry;
}
/**
* @x.category GETSET
*/
public OutgoingConnectionsRegistry getOutgoingConnectionRegistry() {
return outgoingConnectionRegistry;
}
/**
* @x.category GETSET
*/
public void setLogIdFactory(LogIdFactory logIdFactory) {
this.logIdFactory = logIdFactory;
}
}