001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.camel.component.mail; 018 019 import java.io.IOException; 020 import java.io.UnsupportedEncodingException; 021 import java.nio.charset.Charset; 022 import java.nio.charset.IllegalCharsetNameException; 023 import java.util.Enumeration; 024 import java.util.HashMap; 025 import java.util.Iterator; 026 import java.util.Map; 027 028 import javax.activation.DataHandler; 029 import javax.activation.DataSource; 030 import javax.mail.Address; 031 import javax.mail.BodyPart; 032 import javax.mail.Header; 033 import javax.mail.Message; 034 import javax.mail.MessagingException; 035 import javax.mail.Multipart; 036 import javax.mail.Part; 037 import javax.mail.internet.InternetAddress; 038 import javax.mail.internet.MimeBodyPart; 039 import javax.mail.internet.MimeMessage; 040 import javax.mail.internet.MimeMultipart; 041 import javax.mail.util.ByteArrayDataSource; 042 043 import org.apache.camel.Exchange; 044 import org.apache.camel.RuntimeCamelException; 045 import org.apache.camel.converter.IOConverter; 046 import org.apache.camel.converter.ObjectConverter; 047 import org.apache.camel.impl.DefaultHeaderFilterStrategy; 048 import org.apache.camel.spi.HeaderFilterStrategy; 049 import org.apache.camel.util.CollectionHelper; 050 import org.apache.camel.util.ObjectHelper; 051 import org.slf4j.Logger; 052 import org.slf4j.LoggerFactory; 053 054 /** 055 * A Strategy used to convert between a Camel {@link Exchange} and {@link Message} to and 056 * from a Mail {@link MimeMessage} 057 * 058 * @version 059 */ 060 public class MailBinding { 061 062 private static final transient Logger LOG = LoggerFactory.getLogger(MailBinding.class); 063 private HeaderFilterStrategy headerFilterStrategy; 064 private ContentTypeResolver contentTypeResolver; 065 066 public MailBinding() { 067 headerFilterStrategy = new DefaultHeaderFilterStrategy(); 068 } 069 070 public MailBinding(HeaderFilterStrategy headerFilterStrategy, ContentTypeResolver contentTypeResolver) { 071 this.headerFilterStrategy = headerFilterStrategy; 072 this.contentTypeResolver = contentTypeResolver; 073 } 074 075 public void populateMailMessage(MailEndpoint endpoint, MimeMessage mimeMessage, Exchange exchange) 076 throws MessagingException, IOException { 077 078 // camel message headers takes precedence over endpoint configuration 079 if (hasRecipientHeaders(exchange)) { 080 setRecipientFromCamelMessage(mimeMessage, exchange); 081 } else { 082 // fallback to endpoint configuration 083 setRecipientFromEndpointConfiguration(mimeMessage, endpoint); 084 } 085 086 // must have at least one recipients otherwise we do not know where to send the mail 087 if (mimeMessage.getAllRecipients() == null) { 088 throw new IllegalArgumentException("The mail message does not have any recipients set."); 089 } 090 091 // set the subject if it was passed in as an option in the uri. Note: if it is in both the URI 092 // and headers the headers win. 093 String subject = endpoint.getConfiguration().getSubject(); 094 if (subject != null) { 095 mimeMessage.setSubject(subject, IOConverter.getCharsetName(exchange, false)); 096 } 097 098 // append the rest of the headers (no recipients) that could be subject, reply-to etc. 099 appendHeadersFromCamelMessage(mimeMessage, endpoint.getConfiguration(), exchange); 100 101 if (empty(mimeMessage.getFrom())) { 102 // lets default the address to the endpoint destination 103 String from = endpoint.getConfiguration().getFrom(); 104 mimeMessage.setFrom(new InternetAddress(from)); 105 } 106 107 // if there is an alternative body provided, set up a mime multipart alternative message 108 if (hasAlternativeBody(endpoint.getConfiguration(), exchange)) { 109 createMultipartAlternativeMessage(mimeMessage, endpoint.getConfiguration(), exchange); 110 } else { 111 if (exchange.getIn().hasAttachments()) { 112 appendAttachmentsFromCamel(mimeMessage, endpoint.getConfiguration(), exchange); 113 } else { 114 populateContentOnMimeMessage(mimeMessage, endpoint.getConfiguration(), exchange); 115 } 116 } 117 } 118 119 protected String determineContentType(MailConfiguration configuration, Exchange exchange) { 120 // see if we got any content type set 121 String contentType = configuration.getContentType(); 122 if (exchange.getIn().getHeader("contentType") != null) { 123 contentType = exchange.getIn().getHeader("contentType", String.class); 124 } else if (exchange.getIn().getHeader(Exchange.CONTENT_TYPE) != null) { 125 contentType = exchange.getIn().getHeader(Exchange.CONTENT_TYPE, String.class); 126 } 127 128 // fix content type to include a space after semi colon if missing 129 if (contentType != null && contentType.contains(";")) { 130 String before = ObjectHelper.before(contentType, ";"); 131 String charset = determineCharSet(configuration, exchange); 132 133 if (before != null && charset == null) { 134 contentType = before.trim(); 135 } else if (before != null && charset != null) { 136 contentType = before.trim() + "; charset=" + charset; 137 } 138 } 139 140 // set the charset if exchange has the charset name as fall back 141 if (contentType != null && !contentType.contains(";") && IOConverter.getCharsetName(exchange, false) != null) { 142 contentType = contentType.trim() + "; charset=" + IOConverter.getCharsetName(exchange, false); 143 } 144 145 if (LOG.isTraceEnabled()) { 146 LOG.trace("Determined Content-Type: " + contentType); 147 } 148 149 return contentType; 150 } 151 152 protected String determineCharSet(MailConfiguration configuration, Exchange exchange) { 153 154 // see if we got any content type set 155 String contentType = configuration.getContentType(); 156 if (exchange.getIn().getHeader("contentType") != null) { 157 contentType = exchange.getIn().getHeader("contentType", String.class); 158 } else if (exchange.getIn().getHeader(Exchange.CONTENT_TYPE) != null) { 159 contentType = exchange.getIn().getHeader(Exchange.CONTENT_TYPE, String.class); 160 } 161 162 // fix content type to include a space after semi colon if missing 163 if (contentType != null && contentType.contains(";")) { 164 String after = ObjectHelper.after(contentType, ";"); 165 166 // after is the charset lets see if its given and a valid charset 167 if (after != null) { 168 String charset = IOConverter.normalizeCharset(ObjectHelper.after(after, "=")); 169 if (charset != null) { 170 boolean supported; 171 try { 172 supported = Charset.isSupported(charset); 173 } catch (IllegalCharsetNameException e) { 174 supported = false; 175 } 176 if (supported) { 177 return charset; 178 } else if (!configuration.isIgnoreUnsupportedCharset()) { 179 return charset; 180 } else if (configuration.isIgnoreUnsupportedCharset()) { 181 LOG.warn("Charset: " + charset + " is not supported, will fallback to use platform default instead."); 182 return null; 183 } 184 } 185 } 186 } 187 188 // Using the charset header of exchange as a fall back 189 return IOConverter.getCharsetName(exchange, false); 190 191 192 193 } 194 195 protected String populateContentOnMimeMessage(MimeMessage part, MailConfiguration configuration, Exchange exchange) 196 throws MessagingException, IOException { 197 198 String contentType = determineContentType(configuration, exchange); 199 200 if (LOG.isTraceEnabled()) { 201 LOG.trace("Using Content-Type " + contentType + " for MimeMessage: " + part); 202 } 203 204 // always store content in a byte array data store to avoid various content type and charset issues 205 DataSource ds = new ByteArrayDataSource(exchange.getIn().getBody(String.class), contentType); 206 part.setDataHandler(new DataHandler(ds)); 207 208 // set the content type header afterwards 209 part.setHeader("Content-Type", contentType); 210 211 return contentType; 212 } 213 214 protected String populateContentOnBodyPart(BodyPart part, MailConfiguration configuration, Exchange exchange) 215 throws MessagingException, IOException { 216 217 String contentType = determineContentType(configuration, exchange); 218 219 if (LOG.isTraceEnabled()) { 220 LOG.trace("Using Content-Type " + contentType + " for BodyPart: " + part); 221 } 222 223 // always store content in a byte array data store to avoid various content type and charset issues 224 DataSource ds = new ByteArrayDataSource(exchange.getIn().getBody(String.class), contentType); 225 part.setDataHandler(new DataHandler(ds)); 226 227 // set the content type header afterwards 228 part.setHeader("Content-Type", contentType); 229 230 return contentType; 231 } 232 233 /** 234 * Extracts the body from the Mail message 235 */ 236 public Object extractBodyFromMail(Exchange exchange, MailMessage mailMessage) { 237 Message message = mailMessage.getMessage(); 238 try { 239 return message.getContent(); 240 } catch (Exception e) { 241 // try to fix message in case it has an unsupported encoding in the Content-Type header 242 UnsupportedEncodingException uee = ObjectHelper.getException(UnsupportedEncodingException.class, e); 243 if (uee != null) { 244 LOG.debug("Unsupported encoding detected: " + uee.getMessage()); 245 try { 246 String contentType = message.getContentType(); 247 String type = ObjectHelper.before(contentType, "charset="); 248 if (type != null) { 249 // try again with fixed content type 250 LOG.debug("Trying to extract mail message again with fixed Content-Type: " + type); 251 // Since message is read-only, we need to use a copy 252 MimeMessage messageCopy = new MimeMessage((MimeMessage)message); 253 messageCopy.setHeader("Content-Type", type); 254 Object body = messageCopy.getContent(); 255 // If we got this far, our fix worked... 256 // Replace the MailMessage's Message with the copy 257 mailMessage.setMessage(messageCopy); 258 return body; 259 } 260 } catch (Exception e2) { 261 // fall through and let original exception be thrown 262 } 263 } 264 265 throw new RuntimeCamelException("Failed to extract body due to: " + e.getMessage() 266 + ". Exchange: " + exchange + ". Message: " + message, e); 267 } 268 } 269 270 /** 271 * Parses the attachments of the given mail message and adds them to the map 272 * 273 * @param message the mail message with attachments 274 * @param map the map to add found attachments (attachmentFilename is the key) 275 */ 276 public void extractAttachmentsFromMail(Message message, Map<String, DataHandler> map) 277 throws javax.mail.MessagingException, IOException { 278 279 LOG.trace("Extracting attachments +++ start +++"); 280 281 Object content = message.getContent(); 282 if (content instanceof Multipart) { 283 extractAttachmentsFromMultipart((Multipart)content, map); 284 } else if (content != null) { 285 LOG.trace("No attachments to extract as content is not Multipart: " + content.getClass().getName()); 286 } 287 288 LOG.trace("Extracting attachments +++ done +++"); 289 } 290 291 protected void extractAttachmentsFromMultipart(Multipart mp, Map<String, DataHandler> map) 292 throws javax.mail.MessagingException, IOException { 293 294 for (int i = 0; i < mp.getCount(); i++) { 295 Part part = mp.getBodyPart(i); 296 LOG.trace("Part #" + i + ": " + part); 297 298 if (part.isMimeType("multipart/*")) { 299 LOG.trace("Part #" + i + ": is mimetype: multipart/*"); 300 extractAttachmentsFromMultipart((Multipart)part.getContent(), map); 301 } else { 302 String disposition = part.getDisposition(); 303 if (LOG.isTraceEnabled()) { 304 LOG.trace("Part #" + i + ": Disposition: " + part.getDisposition()); 305 LOG.trace("Part #" + i + ": Description: " + part.getDescription()); 306 LOG.trace("Part #" + i + ": ContentType: " + part.getContentType()); 307 LOG.trace("Part #" + i + ": FileName: " + part.getFileName()); 308 LOG.trace("Part #" + i + ": Size: " + part.getSize()); 309 LOG.trace("Part #" + i + ": LineCount: " + part.getLineCount()); 310 } 311 312 if (disposition != null && (disposition.equalsIgnoreCase(Part.ATTACHMENT) || disposition.equalsIgnoreCase(Part.INLINE))) { 313 // only add named attachments 314 String fileName = part.getFileName(); 315 if (fileName != null) { 316 LOG.debug("Mail contains file attachment: " + fileName); 317 if (!map.containsKey(fileName)) { 318 // Parts marked with a disposition of Part.ATTACHMENT are clearly attachments 319 map.put(fileName, part.getDataHandler()); 320 } else { 321 LOG.warn("Cannot extract duplicate attachment: " + fileName); 322 } 323 } 324 } 325 } 326 } 327 } 328 329 /** 330 * Appends the Mail headers from the Camel {@link MailMessage} 331 */ 332 protected void appendHeadersFromCamelMessage(MimeMessage mimeMessage, MailConfiguration configuration, Exchange exchange) 333 throws MessagingException { 334 335 for (Map.Entry<String, Object> entry : exchange.getIn().getHeaders().entrySet()) { 336 String headerName = entry.getKey(); 337 Object headerValue = entry.getValue(); 338 if (headerValue != null) { 339 if (headerFilterStrategy != null 340 && !headerFilterStrategy.applyFilterToCamelHeaders(headerName, headerValue, exchange)) { 341 if (headerName.equalsIgnoreCase("subject")) { 342 mimeMessage.setSubject(asString(exchange, headerValue), IOConverter.getCharsetName(exchange, false)); 343 continue; 344 } 345 if (isRecipientHeader(headerName)) { 346 // skip any recipients as they are handled specially 347 continue; 348 } 349 350 // alternative body should also be skipped 351 if (headerName.equalsIgnoreCase(configuration.getAlternativeBodyHeader())) { 352 // skip alternative body 353 continue; 354 } 355 356 // Mail messages can repeat the same header... 357 if (ObjectConverter.isCollection(headerValue)) { 358 Iterator iter = ObjectHelper.createIterator(headerValue); 359 while (iter.hasNext()) { 360 Object value = iter.next(); 361 mimeMessage.addHeader(headerName, asString(exchange, value)); 362 } 363 } else { 364 mimeMessage.setHeader(headerName, asString(exchange, headerValue)); 365 } 366 } 367 } 368 } 369 } 370 371 private void setRecipientFromCamelMessage(MimeMessage mimeMessage, Exchange exchange) throws MessagingException { 372 for (Map.Entry<String, Object> entry : exchange.getIn().getHeaders().entrySet()) { 373 String headerName = entry.getKey(); 374 Object headerValue = entry.getValue(); 375 if (headerValue != null && isRecipientHeader(headerName)) { 376 // special handling of recipients 377 if (ObjectConverter.isCollection(headerValue)) { 378 Iterator iter = ObjectHelper.createIterator(headerValue); 379 while (iter.hasNext()) { 380 Object recipient = iter.next(); 381 appendRecipientToMimeMessage(mimeMessage, headerName, asString(exchange, recipient)); 382 } 383 } else { 384 appendRecipientToMimeMessage(mimeMessage, headerName, asString(exchange, headerValue)); 385 } 386 } 387 } 388 } 389 390 /** 391 * Appends the Mail headers from the endpoint configuration. 392 */ 393 protected void setRecipientFromEndpointConfiguration(MimeMessage mimeMessage, MailEndpoint endpoint) 394 throws MessagingException { 395 396 Map<Message.RecipientType, String> recipients = endpoint.getConfiguration().getRecipients(); 397 if (recipients.containsKey(Message.RecipientType.TO)) { 398 appendRecipientToMimeMessage(mimeMessage, Message.RecipientType.TO.toString(), recipients.get(Message.RecipientType.TO)); 399 } 400 if (recipients.containsKey(Message.RecipientType.CC)) { 401 appendRecipientToMimeMessage(mimeMessage, Message.RecipientType.CC.toString(), recipients.get(Message.RecipientType.CC)); 402 } 403 if (recipients.containsKey(Message.RecipientType.BCC)) { 404 appendRecipientToMimeMessage(mimeMessage, Message.RecipientType.BCC.toString(), recipients.get(Message.RecipientType.BCC)); 405 } 406 } 407 408 /** 409 * Appends the Mail attachments from the Camel {@link MailMessage} 410 */ 411 protected void appendAttachmentsFromCamel(MimeMessage mimeMessage, MailConfiguration configuration, Exchange exchange) 412 throws MessagingException, IOException { 413 414 // Put parts in message 415 mimeMessage.setContent(createMixedMultipartAttachments(configuration, exchange)); 416 } 417 418 private MimeMultipart createMixedMultipartAttachments(MailConfiguration configuration, Exchange exchange) 419 throws MessagingException, IOException { 420 421 // fill the body with text 422 MimeMultipart multipart = new MimeMultipart(); 423 multipart.setSubType("mixed"); 424 addBodyToMultipart(configuration, multipart, exchange); 425 String partDisposition = configuration.isUseInlineAttachments() ? Part.INLINE : Part.ATTACHMENT; 426 if (exchange.getIn().hasAttachments()) { 427 addAttachmentsToMultipart(multipart, partDisposition, exchange); 428 } 429 return multipart; 430 } 431 432 protected void addAttachmentsToMultipart(MimeMultipart multipart, String partDisposition, Exchange exchange) throws MessagingException { 433 LOG.trace("Adding attachments +++ start +++"); 434 int i = 0; 435 for (Map.Entry<String, DataHandler> entry : exchange.getIn().getAttachments().entrySet()) { 436 String attachmentFilename = entry.getKey(); 437 DataHandler handler = entry.getValue(); 438 439 if (LOG.isTraceEnabled()) { 440 LOG.trace("Attachment #" + i + ": Disposition: " + partDisposition); 441 LOG.trace("Attachment #" + i + ": DataHandler: " + handler); 442 LOG.trace("Attachment #" + i + ": FileName: " + attachmentFilename); 443 } 444 if (handler != null) { 445 if (shouldAddAttachment(exchange, attachmentFilename, handler)) { 446 // Create another body part 447 BodyPart messageBodyPart = new MimeBodyPart(); 448 // Set the data handler to the attachment 449 messageBodyPart.setDataHandler(handler); 450 451 if (attachmentFilename.toLowerCase().startsWith("cid:")) { 452 // add a Content-ID header to the attachment 453 // must use angle brackets according to RFC: http://www.ietf.org/rfc/rfc2392.txt 454 messageBodyPart.addHeader("Content-ID", "<" + attachmentFilename.substring(4) + ">"); 455 // Set the filename without the cid 456 messageBodyPart.setFileName(attachmentFilename.substring(4)); 457 } else { 458 // Set the filename 459 messageBodyPart.setFileName(attachmentFilename); 460 } 461 462 LOG.trace("Attachment #" + i + ": ContentType: " + messageBodyPart.getContentType()); 463 464 if (contentTypeResolver != null) { 465 String contentType = contentTypeResolver.resolveContentType(attachmentFilename); 466 LOG.trace("Attachment #" + i + ": Using content type resolver: " + contentTypeResolver + " resolved content type as: " + contentType); 467 if (contentType != null) { 468 String value = contentType + "; name=" + attachmentFilename; 469 messageBodyPart.setHeader("Content-Type", value); 470 LOG.trace("Attachment #" + i + ": ContentType: " + messageBodyPart.getContentType()); 471 } 472 } 473 474 // Set Disposition 475 messageBodyPart.setDisposition(partDisposition); 476 // Add part to multipart 477 multipart.addBodyPart(messageBodyPart); 478 } else { 479 LOG.trace("shouldAddAttachment: false"); 480 } 481 } else { 482 LOG.warn("Cannot add attachment: " + attachmentFilename + " as DataHandler is null"); 483 } 484 i++; 485 } 486 LOG.trace("Adding attachments +++ done +++"); 487 } 488 489 protected void createMultipartAlternativeMessage(MimeMessage mimeMessage, MailConfiguration configuration, Exchange exchange) 490 throws MessagingException, IOException { 491 492 MimeMultipart multipartAlternative = new MimeMultipart("alternative"); 493 mimeMessage.setContent(multipartAlternative); 494 495 MimeBodyPart plainText = new MimeBodyPart(); 496 plainText.setText(getAlternativeBody(configuration, exchange), determineCharSet(configuration, exchange)); 497 // remove the header with the alternative mail now that we got it 498 // otherwise it might end up twice in the mail reader 499 exchange.getIn().removeHeader(configuration.getAlternativeBodyHeader()); 500 multipartAlternative.addBodyPart(plainText); 501 502 // if there are no attachments, add the body to the same mulitpart message 503 if (!exchange.getIn().hasAttachments()) { 504 addBodyToMultipart(configuration, multipartAlternative, exchange); 505 } else { 506 // if there are attachments, but they aren't set to be inline, add them to 507 // treat them as normal. It will append a multipart-mixed with the attachments and the body text 508 if (!configuration.isUseInlineAttachments()) { 509 BodyPart mixedAttachments = new MimeBodyPart(); 510 mixedAttachments.setContent(createMixedMultipartAttachments(configuration, exchange)); 511 multipartAlternative.addBodyPart(mixedAttachments); 512 } else { 513 // if the attachments are set to be inline, attach them as inline attachments 514 MimeMultipart multipartRelated = new MimeMultipart("related"); 515 BodyPart related = new MimeBodyPart(); 516 517 related.setContent(multipartRelated); 518 multipartAlternative.addBodyPart(related); 519 520 addBodyToMultipart(configuration, multipartRelated, exchange); 521 522 addAttachmentsToMultipart(multipartRelated, Part.INLINE, exchange); 523 } 524 } 525 } 526 527 protected void addBodyToMultipart(MailConfiguration configuration, MimeMultipart activeMultipart, Exchange exchange) 528 throws MessagingException, IOException { 529 530 BodyPart bodyMessage = new MimeBodyPart(); 531 populateContentOnBodyPart(bodyMessage, configuration, exchange); 532 activeMultipart.addBodyPart(bodyMessage); 533 } 534 535 /** 536 * Strategy to allow filtering of attachments which are added on the Mail message 537 */ 538 protected boolean shouldAddAttachment(Exchange exchange, String attachmentFilename, DataHandler handler) { 539 return true; 540 } 541 542 protected Map<String, Object> extractHeadersFromMail(Message mailMessage, Exchange exchange) throws MessagingException { 543 Map<String, Object> answer = new HashMap<String, Object>(); 544 Enumeration names = mailMessage.getAllHeaders(); 545 546 while (names.hasMoreElements()) { 547 Header header = (Header) names.nextElement(); 548 String value = header.getValue(); 549 if (headerFilterStrategy != null && !headerFilterStrategy.applyFilterToExternalHeaders(header.getName(), value, exchange)) { 550 CollectionHelper.appendValue(answer, header.getName(), value); 551 } 552 } 553 554 return answer; 555 } 556 557 private static void appendRecipientToMimeMessage(MimeMessage mimeMessage, String type, String recipient) 558 throws MessagingException { 559 560 // we support that multi recipient can be given as a string separated by comma or semicolon 561 // regex ignores comma and semicolon inside of double quotes 562 String[] lines = recipient.split("[,;]++(?=(?:(?:[^\\\"]*+\\\"){2})*+[^\\\"]*+$)"); 563 for (String line : lines) { 564 line = line.trim(); 565 mimeMessage.addRecipients(asRecipientType(type), line); 566 } 567 } 568 569 /** 570 * Does the given camel message contain any To, CC or BCC header names? 571 */ 572 private static boolean hasRecipientHeaders(Exchange exchange) { 573 for (String key : exchange.getIn().getHeaders().keySet()) { 574 if (isRecipientHeader(key)) { 575 return true; 576 } 577 } 578 return false; 579 } 580 581 protected static boolean hasAlternativeBody(MailConfiguration configuration, Exchange exchange) { 582 return getAlternativeBody(configuration, exchange) != null; 583 } 584 585 protected static String getAlternativeBody(MailConfiguration configuration, Exchange exchange) { 586 String alternativeBodyHeader = configuration.getAlternativeBodyHeader(); 587 return exchange.getIn().getHeader(alternativeBodyHeader, java.lang.String.class); 588 } 589 590 /** 591 * Is the given key a mime message recipient header (To, CC or BCC) 592 */ 593 private static boolean isRecipientHeader(String key) { 594 if (Message.RecipientType.TO.toString().equalsIgnoreCase(key)) { 595 return true; 596 } else if (Message.RecipientType.CC.toString().equalsIgnoreCase(key)) { 597 return true; 598 } else if (Message.RecipientType.BCC.toString().equalsIgnoreCase(key)) { 599 return true; 600 } 601 return false; 602 } 603 604 /** 605 * Returns the RecipientType object. 606 */ 607 private static Message.RecipientType asRecipientType(String type) { 608 if (Message.RecipientType.TO.toString().equalsIgnoreCase(type)) { 609 return Message.RecipientType.TO; 610 } else if (Message.RecipientType.CC.toString().equalsIgnoreCase(type)) { 611 return Message.RecipientType.CC; 612 } else if (Message.RecipientType.BCC.toString().equalsIgnoreCase(type)) { 613 return Message.RecipientType.BCC; 614 } 615 throw new IllegalArgumentException("Unknown recipient type: " + type); 616 } 617 618 619 private static boolean empty(Address[] addresses) { 620 return addresses == null || addresses.length == 0; 621 } 622 623 private static String asString(Exchange exchange, Object value) { 624 return exchange.getContext().getTypeConverter().convertTo(String.class, exchange, value); 625 } 626 627 }