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