use of javax.mail.SendFailedException in project zm-mailbox by Zimbra.
the class MailSender method sendMessage.
/**
* @return a Collection of successfully sent recipient Addresses
*/
protected Collection<Address> sendMessage(Mailbox mbox, final MimeMessage mm, Collection<RollbackData> rollbacks) throws SafeMessagingException, IOException {
// send the message via SMTP
HashSet<Address> sentAddresses = new HashSet<Address>();
mCurrentHostIndex = 0;
String hostname = getNextHost();
try {
// Initialize recipient addresses
Address[] rcptAddresses = getRecipients(mm);
if (rcptAddresses == null || rcptAddresses.length == 0)
throw new SendFailedException("No recipient addresses");
while (true) {
try {
logMessage(mm, rcptAddresses, mEnvelopeFrom, hostname, null != mOriginalMessageId ? mOriginalMessageId.toString() : null, mUploads, mReplyType, null);
if (hostname != null) {
sendMessageToHost(hostname, mm, rcptAddresses);
} else {
Transport.send(mm, rcptAddresses);
}
Collections.addAll(sentAddresses, rcptAddresses);
break;
} catch (SendFailedException sfe) {
throw sfe;
} catch (MessagingException e) {
Exception chained = e.getNextException();
if (chained instanceof SocketException || chained instanceof UnknownHostException) {
String hostString = (hostname != null ? " " + hostname : "");
ZimbraLog.smtp.warn("Unable to connect to SMTP server%s: %s.", hostString, chained.toString());
if (mTrackBadHosts) {
JMSession.markSmtpHostBad(hostname);
}
hostname = getNextHost();
if (hostname == null) {
throw e;
}
ZimbraLog.smtp.info("Attempting to send to %s.", hostname);
} else {
throw e;
}
}
}
} catch (SendFailedException e) {
// skip roll backs for partial send failure cases!
if (isSendPartial())
throw new SafeSendFailedException(e);
for (RollbackData rdata : rollbacks) {
if (rdata != null) {
rdata.rollback();
}
}
throw new SafeSendFailedException(e);
} catch (MessagingException e) {
for (RollbackData rdata : rollbacks) {
if (rdata != null) {
rdata.rollback();
}
}
throw new SafeMessagingException(e);
} catch (RuntimeException e) {
for (RollbackData rdata : rollbacks) {
if (rdata != null) {
rdata.rollback();
}
}
throw e;
}
return sentAddresses;
}
use of javax.mail.SendFailedException in project zm-mailbox by Zimbra.
the class SmtpTransport method notify.
private void notify(Exception ex, Message msg, Address[] addrs) throws SendFailedException {
Set<String> validRcpts = connection.getValidRecipients();
Set<String> invalidRcpts = connection.getInvalidRecipients();
List<Address> validAddrs = new ArrayList<Address>(validRcpts.size());
List<Address> invalidAddrs = new ArrayList<Address>(invalidRcpts.size());
for (Address addr : addrs) {
if (addr instanceof InternetAddress) {
InternetAddress iaddr = (InternetAddress) addr;
if (validRcpts.contains(iaddr.getAddress())) {
validAddrs.add(iaddr);
} else if (invalidRcpts.contains(iaddr.getAddress())) {
invalidAddrs.add(iaddr);
}
}
}
Address[] validSent = Iterables.toArray(validAddrs, Address.class);
Address[] validUnsent = new Address[0];
Address[] invalid = Iterables.toArray(invalidAddrs, Address.class);
int notify = ex != null ? TransportEvent.MESSAGE_NOT_DELIVERED : invalid.length > 0 ? TransportEvent.MESSAGE_PARTIALLY_DELIVERED : TransportEvent.MESSAGE_DELIVERED;
notifyTransportListeners(notify, validSent, validUnsent, invalid, msg);
switch(notify) {
case TransportEvent.MESSAGE_NOT_DELIVERED:
throw new SendFailedException("MESSAGE_NOT_DELIVERED", ex, validSent, validUnsent, invalid);
case TransportEvent.MESSAGE_PARTIALLY_DELIVERED:
throw new SendFailedException("MESSAGE_PARTIALLY_DELIVERED", ex, validSent, validUnsent, invalid);
}
}
use of javax.mail.SendFailedException in project zm-mailbox by Zimbra.
the class CalendarRequest method sendCalendarMessageInternal.
/**
* Send an iCalendar email message and optionally create/update/cancel
* corresponding appointment/invite in sender's calendar.
* @param zsc
* @param apptFolderId
* @param acct
* @param mbox
* @param csd
* @param response
* @param updateOwnAppointment if true, corresponding change is made to
* sender's calendar
* @param forceSend
* @param sendQueue
* @param updatePrevFolders if true, updates prevFolders field with Trash in database
* @return
* @throws ServiceException
*/
private static Element sendCalendarMessageInternal(ZimbraSoapContext zsc, OperationContext octxt, int apptFolderId, Account acct, Mailbox mbox, CalSendData csd, Element response, boolean updateOwnAppointment, boolean forceSend, MailSendQueue sendQueue, boolean updatePrevFolders) throws ServiceException {
boolean onBehalfOf = isOnBehalfOfRequest(zsc);
boolean notifyOwner = onBehalfOf && acct.getBooleanAttr(Provisioning.A_zimbraPrefCalendarNotifyDelegatedChanges, false);
if (notifyOwner) {
try {
InternetAddress addr = AccountUtil.getFriendlyEmailAddress(acct);
csd.mMm.addRecipient(javax.mail.Message.RecipientType.TO, addr);
} catch (MessagingException e) {
throw ServiceException.FAILURE("count not add calendar owner to recipient list", e);
}
}
// in a non-delegated request.
if (!onBehalfOf) {
String[] aliases = acct.getMailAlias();
String[] addrs;
if (aliases != null && aliases.length > 0) {
addrs = new String[aliases.length + 1];
addrs[0] = acct.getAttr(Provisioning.A_mail);
for (int i = 0; i < aliases.length; i++) {
addrs[i + 1] = aliases[i];
}
} else {
addrs = new String[1];
addrs[0] = acct.getAttr(Provisioning.A_mail);
}
try {
Mime.removeRecipients(csd.mMm, addrs);
} catch (MessagingException e) {
}
}
ParsedMessage pm = new ParsedMessage(csd.mMm, false);
if (csd.mInvite.getFragment() == null || csd.mInvite.getFragment().equals("")) {
csd.mInvite.setFragment(pm.getFragment(acct.getLocale()));
}
boolean willNotify = false;
if (!csd.mDontNotifyAttendees) {
try {
Address[] rcpts = csd.mMm.getAllRecipients();
willNotify = rcpts != null && rcpts.length > 0;
} catch (MessagingException e) {
throw ServiceException.FAILURE("Checking recipients of outgoing msg ", e);
}
}
// Validate the addresses first.
if (!csd.mInvite.isCancel() && !forceSend && willNotify) {
try {
MailUtil.validateRcptAddresses(JMSession.getSmtpSession(mbox.getAccount()), csd.mMm.getAllRecipients());
} catch (MessagingException mex) {
if (mex instanceof SendFailedException) {
SendFailedException sfex = (SendFailedException) mex;
throw MailServiceException.SEND_ABORTED_ADDRESS_FAILURE("invalid addresses", sfex, sfex.getInvalidAddresses(), sfex.getValidUnsentAddresses());
}
}
}
AddInviteData aid = null;
File tempMmFile = null;
boolean queued = false;
try {
if (willNotify) {
// Write out the MimeMessage to a temp file and create a new MimeMessage from the file.
// If we don't do this, we get into trouble during modify appointment call. If the blob
// is bigger than the streaming threshold (e.g. appointment has a big attachment), the
// MimeMessage object is attached to the current blob file. But the Mailbox.addInvite()
// call below updates the blob to a new mod_content (hence new path). The attached blob
// thus having been deleted, the MainSender.sendMimeMessage() call that follows will attempt
// to read from a non-existent file and fail. We can avoid this situation by writing the
// to-be-emailed mime message to a temp file, thus detaching it from the appointment's
// current blob file. This is inefficient, but safe.
OutputStream os = null;
InputStream is = null;
try {
tempMmFile = File.createTempFile("zcal", "tmp");
os = new FileOutputStream(tempMmFile);
csd.mMm.writeTo(os);
ByteUtil.closeStream(os);
os = null;
is = new ZSharedFileInputStream(tempMmFile);
csd.mMm = new FixedMimeMessage(JMSession.getSmtpSession(acct), is);
} catch (IOException e) {
if (tempMmFile != null)
tempMmFile.delete();
throw ServiceException.FAILURE("error creating calendar message content", e);
} catch (MessagingException e) {
if (tempMmFile != null)
tempMmFile.delete();
throw ServiceException.FAILURE("error creating calendar message content", e);
} finally {
ByteUtil.closeStream(os);
ByteUtil.closeStream(is);
}
}
// because email send will delete uploaded attachments as a side-effect.
if (updateOwnAppointment) {
aid = mbox.addInvite(octxt, csd.mInvite, apptFolderId, pm, updatePrevFolders);
}
// Next, notify any attendees.
if (willNotify) {
MailSendQueueEntry entry = new MailSendQueueEntry(octxt, mbox, csd, tempMmFile);
sendQueue.add(entry);
queued = true;
}
} finally {
// Delete the temp file if it wasn't queued.
if (tempMmFile != null && !queued) {
tempMmFile.delete();
}
}
if (updateOwnAppointment && response != null && aid != null) {
csd.mAddInvData = aid;
ItemIdFormatter ifmt = new ItemIdFormatter(zsc);
String id = ifmt.formatItemId(aid.calItemId);
response.addAttribute(MailConstants.A_CAL_ID, id);
if (csd.mInvite.isEvent())
// for backward compat
response.addAttribute(MailConstants.A_APPT_ID_DEPRECATE_ME, id);
response.addAttribute(MailConstants.A_CAL_INV_ID, ifmt.formatItemId(aid.calItemId, aid.invId));
if (Invite.isOrganizerMethod(csd.mInvite.getMethod())) {
response.addAttribute(MailConstants.A_MODIFIED_SEQUENCE, aid.modSeq);
response.addAttribute(MailConstants.A_REVISION, aid.rev);
}
}
return response;
}
use of javax.mail.SendFailedException in project zm-mailbox by Zimbra.
the class SmtpTransportTest method mailFromError.
@Test(timeout = 3000)
public void mailFromError() throws Exception {
server = MockTcpServer.scenario().sendLine("220 test ready").recvLine().sendLine("250 OK").recvLine().sendLine("451 error").recvLine().build().start(PORT);
Session session = JMSession.getSession();
Transport transport = session.getTransport("smtp");
transport.connect("localhost", PORT, null, null);
String raw = "From: sender@zimbra.com\nTo: rcpt@zimbra.com\n" + "Subject: test\n\ntest";
MimeMessage msg = new ZMimeMessage(session, new SharedByteArrayInputStream(raw.getBytes(Charsets.ISO_8859_1)));
try {
transport.sendMessage(msg, msg.getAllRecipients());
Assert.fail();
} catch (SendFailedException e) {
Assert.assertEquals(0, e.getValidSentAddresses().length);
Assert.assertEquals(0, e.getValidUnsentAddresses().length);
Assert.assertEquals(0, e.getInvalidAddresses().length);
} finally {
transport.close();
}
server.shutdown(1000);
Assert.assertEquals("EHLO localhost\r\n", server.replay());
Assert.assertEquals("MAIL FROM:<sender@zimbra.com>\r\n", server.replay());
Assert.assertEquals("QUIT\r\n", server.replay());
Assert.assertNull(server.replay());
}
use of javax.mail.SendFailedException in project zm-mailbox by Zimbra.
the class SmtpTransportTest method sendPartially.
@Test(timeout = 3000)
public void sendPartially() throws Exception {
server = MockTcpServer.scenario().sendLine("220 test ready").recvLine().sendLine("250 OK").recvLine().sendLine("250 OK").recvLine().sendLine("250 OK").recvLine().sendLine("550 not found").recvLine().sendLine("550 not found").recvLine().sendLine("354 OK").swallowUntil("\r\n.\r\n").sendLine("250 OK").recvLine().sendLine("221 bye").build().start(PORT);
Session session = JMSession.getSession();
session.getProperties().setProperty("mail.smtp.sendpartial", "true");
Transport transport = session.getTransport("smtp");
transport.connect("localhost", PORT, null, null);
String raw = "From: sender@zimbra.com\n" + "To: rcpt1@zimbra.com, rcpt2@zimbra.com, rcpt3@zimbra.com\nSubject: test\n\ntest";
MimeMessage msg = new ZMimeMessage(session, new SharedByteArrayInputStream(raw.getBytes(Charsets.ISO_8859_1)));
try {
transport.sendMessage(msg, msg.getAllRecipients());
} catch (SendFailedException e) {
Assert.assertEquals(1, e.getValidSentAddresses().length);
Assert.assertEquals(0, e.getValidUnsentAddresses().length);
Assert.assertEquals(2, e.getInvalidAddresses().length);
} finally {
transport.close();
}
server.shutdown(1000);
Assert.assertEquals("EHLO localhost\r\n", server.replay());
Assert.assertEquals("MAIL FROM:<sender@zimbra.com>\r\n", server.replay());
Assert.assertEquals("RCPT TO:<rcpt1@zimbra.com>\r\n", server.replay());
Assert.assertEquals("RCPT TO:<rcpt2@zimbra.com>\r\n", server.replay());
Assert.assertEquals("RCPT TO:<rcpt3@zimbra.com>\r\n", server.replay());
Assert.assertEquals("DATA\r\n", server.replay());
Assert.assertEquals("QUIT\r\n", server.replay());
Assert.assertNull(server.replay());
}
Aggregations