001/*
002 * The MIT License
003 * Copyright (c) 2012 Microsoft Corporation
004 *
005 * Permission is hereby granted, free of charge, to any person obtaining a copy
006 * of this software and associated documentation files (the "Software"), to deal
007 * in the Software without restriction, including without limitation the rights
008 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
009 * copies of the Software, and to permit persons to whom the Software is
010 * furnished to do so, subject to the following conditions:
011 *
012 * The above copyright notice and this permission notice shall be included in
013 * all copies or substantial portions of the Software.
014 *
015 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
016 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
017 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
018 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
019 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
020 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
021 * THE SOFTWARE.
022 */
023
024package microsoft.exchange.webservices.data.core.service.item;
025
026import microsoft.exchange.webservices.data.attribute.Attachable;
027import microsoft.exchange.webservices.data.attribute.ServiceObjectDefinition;
028import microsoft.exchange.webservices.data.core.EwsUtilities;
029import microsoft.exchange.webservices.data.core.ExchangeService;
030import microsoft.exchange.webservices.data.core.PropertySet;
031import microsoft.exchange.webservices.data.core.XmlElementNames;
032import microsoft.exchange.webservices.data.core.service.response.ResponseMessage;
033import microsoft.exchange.webservices.data.core.service.response.SuppressReadReceipt;
034import microsoft.exchange.webservices.data.core.service.schema.EmailMessageSchema;
035import microsoft.exchange.webservices.data.core.service.schema.ServiceObjectSchema;
036import microsoft.exchange.webservices.data.core.enumeration.service.ConflictResolutionMode;
037import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion;
038import microsoft.exchange.webservices.data.core.enumeration.service.MessageDisposition;
039import microsoft.exchange.webservices.data.core.enumeration.service.ResponseMessageType;
040import microsoft.exchange.webservices.data.core.enumeration.property.WellKnownFolderName;
041import microsoft.exchange.webservices.data.core.exception.service.local.ServiceLocalException;
042import microsoft.exchange.webservices.data.property.complex.EmailAddress;
043import microsoft.exchange.webservices.data.property.complex.EmailAddressCollection;
044import microsoft.exchange.webservices.data.property.complex.FolderId;
045import microsoft.exchange.webservices.data.property.complex.ItemAttachment;
046import microsoft.exchange.webservices.data.property.complex.ItemId;
047import microsoft.exchange.webservices.data.property.complex.MessageBody;
048
049import java.util.Arrays;
050
051/**
052 * Represents an e-mail message. Properties available on e-mail messages are
053 * defined in the EmailMessageSchema class.
054 */
055@Attachable
056@ServiceObjectDefinition(xmlElementName = XmlElementNames.Message)
057public class EmailMessage extends Item {
058
059  /**
060   * Initializes an unsaved local instance of EmailMessage. To bind to an
061   * existing e-mail message, use EmailMessage.Bind() instead.
062   *
063   * @param service The ExchangeService object to which the e-mail message will be
064   *                bound.
065   * @throws Exception the exception
066   */
067  public EmailMessage(ExchangeService service) throws Exception {
068    super(service);
069  }
070
071  public EmailMessage(ExchangeService service, ItemId itemId) throws Exception {
072    super(service, itemId);
073  }
074
075  /**
076   * Initializes a new instance of the "EmailMessage" class.
077   *
078   * @param parentAttachment The parent attachment.
079   * @throws Exception the exception
080   */
081  public EmailMessage(ItemAttachment parentAttachment) throws Exception {
082    super(parentAttachment);
083  }
084
085  /**
086   * Binds to an existing e-mail message and loads the specified set of
087   * property.Calling this method results in a call to EWS.
088   *
089   * @param service     the service
090   * @param id          the id
091   * @param propertySet the property set
092   * @return An EmailMessage instance representing the e-mail message
093   * corresponding to the specified Id
094   * @throws Exception the exception
095   */
096  public static EmailMessage bind(ExchangeService service, ItemId id,
097      PropertySet propertySet) throws Exception {
098    return service.bindToItem(EmailMessage.class, id, propertySet);
099
100  }
101
102  /**
103   * Binds to an existing e-mail message and loads its first class
104   * property.Calling this method results in a call to EWS.
105   *
106   * @param service the service
107   * @param id      the id
108   * @return An EmailMessage instance representing the e-mail message
109   * corresponding to the specified Id
110   * @throws Exception the exception
111   */
112  public static EmailMessage bind(ExchangeService service, ItemId id)
113      throws Exception {
114    return EmailMessage.bind(service, id, PropertySet
115        .getFirstClassProperties());
116  }
117
118  /**
119   * Method to return the schema associated with this type of object.
120   *
121   * @return The schema associated with this type of object.
122   */
123  @Override public ServiceObjectSchema getSchema() {
124    return EmailMessageSchema.Instance;
125  }
126
127  /**
128   * Gets the minimum required server version.
129   *
130   * @return Earliest Exchange version in which this service object type is
131   * supported.
132   */
133  @Override public ExchangeVersion getMinimumRequiredServerVersion() {
134    return ExchangeVersion.Exchange2007_SP1;
135  }
136
137  /**
138   * Send message.
139   *
140   * @param parentFolderId     The parent folder id.
141   * @param messageDisposition The message disposition.
142   * @throws Exception the exception
143   */
144  private void internalSend(FolderId parentFolderId,
145      MessageDisposition messageDisposition) throws Exception {
146    this.throwIfThisIsAttachment();
147
148    if (this.isNew()) {
149      if ((this.getAttachments().getCount() == 0) ||
150          (messageDisposition == MessageDisposition.SaveOnly)) {
151        this.internalCreate(parentFolderId, messageDisposition, null);
152      } else {
153        // Bug E14:80316 -- If the message has attachments, save as a
154        // draft (and add attachments) before sending.
155        this.internalCreate(null, // null means use the Drafts folder in
156            // the mailbox of the authenticated
157            // user.
158            MessageDisposition.SaveOnly, null);
159
160        this.getService().sendItem(this, parentFolderId);
161      }
162    } else if (this.isDirty()) {
163      // Validate and save attachments before sending.
164      this.getAttachments().validate();
165      this.getAttachments().save();
166
167      if (this.getPropertyBag().getIsUpdateCallNecessary()) {
168        this.internalUpdate(parentFolderId,
169            ConflictResolutionMode.AutoResolve, messageDisposition,
170            null);
171      } else {
172        this.getService().sendItem(this, parentFolderId);
173      }
174    } else {
175      this.getService().sendItem(this, parentFolderId);
176    }
177
178    // this.internalCreate(parentFolderId, messageDisposition, null);
179  }
180
181  /**
182   * Creates a reply response to the message.
183   *
184   * @param replyAll the reply all
185   * @return A ResponseMessage representing the reply response that can
186   * subsequently be modified and sent.
187   * @throws Exception the exception
188   */
189  public ResponseMessage createReply(boolean replyAll) throws Exception {
190    this.throwIfThisIsNew();
191
192    return new ResponseMessage(this,
193        replyAll ? ResponseMessageType.ReplyAll :
194            ResponseMessageType.Reply);
195  }
196
197  /**
198   * Creates a forward response to the message.
199   *
200   * @return A ResponseMessage representing the forward response that can
201   * subsequently be modified and sent.
202   * @throws Exception the exception
203   */
204  public ResponseMessage createForward() throws Exception {
205    this.throwIfThisIsNew();
206    return new ResponseMessage(this, ResponseMessageType.Forward);
207  }
208
209  /**
210   * Replies to the message. Calling this method results in a call to EWS.
211   *
212   * @param bodyPrefix the body prefix
213   * @param replyAll   the reply all
214   * @throws Exception the exception
215   */
216  public void reply(MessageBody bodyPrefix, boolean replyAll)
217      throws Exception {
218    ResponseMessage responseMessage = this.createReply(replyAll);
219    responseMessage.setBodyPrefix(bodyPrefix);
220    responseMessage.sendAndSaveCopy();
221  }
222
223  /**
224   * Forwards the message. Calling this method results in a call to EWS.
225   *
226   * @param bodyPrefix   the body prefix
227   * @param toRecipients the to recipients
228   * @throws Exception the exception
229   */
230  public void forward(MessageBody bodyPrefix, EmailAddress... toRecipients)
231      throws Exception {
232    if (null != toRecipients) {
233      forward(bodyPrefix, Arrays.asList(toRecipients));
234    }
235  }
236
237  /**
238   * Forwards the message. Calling this method results in a call to EWS.
239   *
240   * @param bodyPrefix   the body prefix
241   * @param toRecipients the to recipients
242   * @throws Exception the exception
243   */
244  public void forward(MessageBody bodyPrefix,
245      Iterable<EmailAddress> toRecipients) throws Exception {
246    ResponseMessage responseMessage = this.createForward();
247
248    responseMessage.setBodyPrefix(bodyPrefix);
249    responseMessage.getToRecipients()
250        .addEmailRange(toRecipients.iterator());
251
252    responseMessage.sendAndSaveCopy();
253  }
254
255  /**
256   * Sends this e-mail message. Calling this method results in at least one
257   * call to EWS.
258   *
259   * @throws Exception the exception
260   */
261  public void send() throws Exception {
262    internalSend(null, MessageDisposition.SendOnly);
263  }
264
265  /**
266   * Sends this e-mail message and saves a copy of it in the specified
267   * folder. SendAndSaveCopy does not work if the message has unsaved
268   * attachments. In that case, the message must first be saved and then sent.
269   * Calling this method results in a call to EWS.
270   *
271   * @param destinationFolderId the destination folder id
272   * @throws Exception the exception
273   */
274  public void sendAndSaveCopy(FolderId destinationFolderId) throws Exception {
275    EwsUtilities.validateParam(destinationFolderId, "destinationFolderId");
276    this.internalSend(destinationFolderId,
277        MessageDisposition.SendAndSaveCopy);
278  }
279
280  /**
281   * Sends this e-mail message and saves a copy of it in the specified
282   * folder. SendAndSaveCopy does not work if the message has unsaved
283   * attachments. In that case, the message must first be saved and then sent.
284   * Calling this method results in a call to EWS.
285   *
286   * @param destinationFolderName the destination folder name
287   * @throws Exception the exception
288   */
289  public void sendAndSaveCopy(WellKnownFolderName destinationFolderName)
290      throws Exception {
291    this.internalSend(new FolderId(destinationFolderName),
292        MessageDisposition.SendAndSaveCopy);
293  }
294
295  /**
296   * Sends this e-mail message and saves a copy of it in the Sent Items
297   * folder. SendAndSaveCopy does not work if the message has unsaved
298   * attachments. In that case, the message must first be saved and then sent.
299   * Calling this method results in a call to EWS.
300   *
301   * @throws Exception the exception
302   */
303  public void sendAndSaveCopy() throws Exception {
304    this.internalSend(new FolderId(WellKnownFolderName.SentItems),
305        MessageDisposition.SendAndSaveCopy);
306  }
307
308  /**
309   * Suppresses the read receipt on the message. Calling this method results
310   * in a call to EWS.
311   *
312   * @throws Exception the exception
313   */
314  public void suppressReadReceipt() throws Exception {
315    this.throwIfThisIsNew();
316    new SuppressReadReceipt(this).internalCreate(null, null);
317  }
318
319  /**
320   * Gets the list of To recipients for the e-mail message.
321   *
322   * @return The list of To recipients for the e-mail message.
323   * @throws ServiceLocalException the service local exception
324   */
325  public EmailAddressCollection getToRecipients()
326      throws ServiceLocalException {
327    return getPropertyBag().getObjectFromPropertyDefinition(
328        EmailMessageSchema.ToRecipients);
329  }
330
331  /**
332   * Gets the list of Bcc recipients for the e-mail message.
333   *
334   * @return the bcc recipients
335   * @throws ServiceLocalException the service local exception
336   */
337  public EmailAddressCollection getBccRecipients()
338      throws ServiceLocalException {
339    return getPropertyBag().getObjectFromPropertyDefinition(
340        EmailMessageSchema.BccRecipients);
341  }
342
343  /**
344   * Gets the list of Cc recipients for the e-mail message.
345   *
346   * @return the cc recipients
347   * @throws ServiceLocalException the service local exception
348   */
349  public EmailAddressCollection getCcRecipients()
350      throws ServiceLocalException {
351    return getPropertyBag().getObjectFromPropertyDefinition(
352        EmailMessageSchema.CcRecipients);
353  }
354
355  /**
356   * Gets the conversation topic of the e-mail message.
357   *
358   * @return the conversation topic
359   * @throws ServiceLocalException the service local exception
360   */
361  public String getConversationTopic() throws ServiceLocalException {
362    return getPropertyBag().getObjectFromPropertyDefinition(
363        EmailMessageSchema.ConversationTopic);
364  }
365
366  /**
367   * Gets the conversation index of the e-mail message.
368   *
369   * @return the conversation index
370   * @throws ServiceLocalException the service local exception
371   */
372  public byte[] getConversationIndex() throws ServiceLocalException {
373    return getPropertyBag().getObjectFromPropertyDefinition(
374        EmailMessageSchema.ConversationIndex);
375  }
376
377  /**
378   * Gets  the "on behalf" sender of the e-mail message.
379   *
380   * @return the from
381   * @throws ServiceLocalException the service local exception
382   */
383  public EmailAddress getFrom() throws ServiceLocalException {
384    return getPropertyBag().getObjectFromPropertyDefinition(
385        EmailMessageSchema.From);
386  }
387
388  /**
389   * Sets the from.
390   *
391   * @param value the new from
392   * @throws Exception the exception
393   */
394  public void setFrom(EmailAddress value) throws Exception {
395    this.getPropertyBag().setObjectFromPropertyDefinition(
396        EmailMessageSchema.From, value);
397  }
398
399  /**
400   * Gets  a value indicating whether this is an associated message.
401   *
402   * @return the checks if is associated
403   * @throws ServiceLocalException the service local exception
404   */
405  @Override
406  public boolean getIsAssociated() throws ServiceLocalException {
407    return super.getIsAssociated();
408  }
409
410  // The "new" keyword is used to expose the setter only on Message types,
411  // because
412  // EWS only supports creation of FAI Message types. IsAssociated is a
413  // readonly
414  // property of the Item type but it is used by the CreateItem web method for
415  // creating
416  // associated messages.
417
418  /**
419   * Sets the checks if is associated.
420   *
421   * @param value the new checks if is associated
422   * @throws Exception the exception
423   */
424  public void setIsAssociated(boolean value) throws Exception {
425    this.getPropertyBag().setObjectFromPropertyDefinition(
426        EmailMessageSchema.IsAssociated, value);
427  }
428
429  /**
430   * Gets a value indicating whether a read receipt is requested for
431   * the e-mail message.
432   *
433   * @return the checks if is delivery receipt requested
434   * @throws ServiceLocalException the service local exception
435   */
436  public Boolean getIsDeliveryReceiptRequested()
437      throws ServiceLocalException {
438    return getPropertyBag().getObjectFromPropertyDefinition(
439        EmailMessageSchema.IsDeliveryReceiptRequested);
440  }
441
442  /**
443   * Sets the checks if is delivery receipt requested.
444   *
445   * @param value the new checks if is delivery receipt requested
446   * @throws Exception the exception
447   */
448  public void setIsDeliveryReceiptRequested(Boolean value) throws Exception {
449    this.getPropertyBag().setObjectFromPropertyDefinition(
450        EmailMessageSchema.IsDeliveryReceiptRequested, value);
451  }
452
453  /**
454   * Gets  a value indicating whether the e-mail message is read.
455   *
456   * @return the checks if is read
457   * @throws ServiceLocalException the service local exception
458   */
459  public Boolean getIsRead() throws ServiceLocalException {
460    return getPropertyBag().getObjectFromPropertyDefinition(
461        EmailMessageSchema.IsRead);
462  }
463
464  /**
465   * Sets the checks if is read.
466   *
467   * @param value the new checks if is read
468   * @throws Exception the exception
469   */
470  public void setIsRead(Boolean value) throws Exception {
471    this.getPropertyBag().setObjectFromPropertyDefinition(
472        EmailMessageSchema.IsRead, value);
473  }
474
475  /**
476   * Gets a value indicating whether a read receipt is requested for
477   * the e-mail message.
478   *
479   * @return the checks if is read receipt requested
480   * @throws ServiceLocalException the service local exception
481   */
482  public Boolean getIsReadReceiptRequested() throws ServiceLocalException {
483    return getPropertyBag().getObjectFromPropertyDefinition(
484        EmailMessageSchema.IsReadReceiptRequested);
485  }
486
487  /**
488   * Sets the checks if is read receipt requested.
489   *
490   * @param value the new checks if is read receipt requested
491   * @throws Exception the exception
492   */
493  public void setIsReadReceiptRequested(Boolean value) throws Exception {
494    this.getPropertyBag().setObjectFromPropertyDefinition(
495        EmailMessageSchema.IsReadReceiptRequested, value);
496  }
497
498  /**
499   * Gets  a value indicating whether a response is requested for the
500   * e-mail message.
501   *
502   * @return the checks if is response requested
503   * @throws ServiceLocalException the service local exception
504   */
505  public Boolean getIsResponseRequested() throws ServiceLocalException {
506    return getPropertyBag().getObjectFromPropertyDefinition(
507        EmailMessageSchema.IsResponseRequested);
508  }
509
510  /**
511   * Sets the checks if is response requested.
512   *
513   * @param value the new checks if is response requested
514   * @throws Exception the exception
515   */
516  public void setIsResponseRequested(Boolean value) throws Exception {
517    this.getPropertyBag().setObjectFromPropertyDefinition(
518        EmailMessageSchema.IsResponseRequested, value);
519  }
520
521  /**
522   * Gets the Internat Message Id of the e-mail message.
523   *
524   * @return the internet message id
525   * @throws ServiceLocalException the service local exception
526   */
527  public String getInternetMessageId() throws ServiceLocalException {
528    return getPropertyBag().getObjectFromPropertyDefinition(
529        EmailMessageSchema.InternetMessageId);
530  }
531
532  /**
533   * Gets  the references of the e-mail message.
534   *
535   * @return the references
536   * @throws ServiceLocalException the service local exception
537   */
538  public String getReferences() throws ServiceLocalException {
539    return getPropertyBag().getObjectFromPropertyDefinition(
540        EmailMessageSchema.References);
541  }
542
543  /**
544   * Sets the references.
545   *
546   * @param value the new references
547   * @throws Exception the exception
548   */
549  public void setReferences(String value) throws Exception {
550    this.getPropertyBag().setObjectFromPropertyDefinition(
551        EmailMessageSchema.References, value);
552  }
553
554  /**
555   * Gets a list of e-mail addresses to which replies should be addressed.
556   *
557   * @return the reply to
558   * @throws ServiceLocalException the service local exception
559   */
560  public EmailAddressCollection getReplyTo() throws ServiceLocalException {
561    return getPropertyBag().getObjectFromPropertyDefinition(
562        EmailMessageSchema.ReplyTo);
563  }
564
565  /**
566   * Gets  the sender of the e-mail message.
567   *
568   * @return the sender
569   * @throws ServiceLocalException the service local exception
570   */
571  public EmailAddress getSender() throws ServiceLocalException {
572    return getPropertyBag().getObjectFromPropertyDefinition(
573        EmailMessageSchema.Sender);
574  }
575
576  /**
577   * Sets the sender.
578   *
579   * @param value the new sender
580   * @throws Exception the exception
581   */
582  public void setSender(EmailAddress value) throws Exception {
583    this.getPropertyBag().setObjectFromPropertyDefinition(
584        EmailMessageSchema.Sender, value);
585  }
586
587  /**
588   * Gets the ReceivedBy property of the e-mail message.
589   *
590   * @return the received by
591   * @throws ServiceLocalException the service local exception
592   */
593  public EmailAddress getReceivedBy() throws ServiceLocalException {
594    return getPropertyBag().getObjectFromPropertyDefinition(
595        EmailMessageSchema.ReceivedBy);
596  }
597
598  /**
599   * Gets the ReceivedRepresenting property of the e-mail message.
600   *
601   * @return the received representing
602   * @throws ServiceLocalException the service local exception
603   */
604  public EmailAddress getReceivedRepresenting() throws ServiceLocalException {
605    return getPropertyBag().getObjectFromPropertyDefinition(
606        EmailMessageSchema.ReceivedRepresenting);
607  }
608}