Add another backup method to mirror creation
authorThomas
Wed, 13 Mar 2019 13:50:02 +0100
changeset 25989ec2fef7baea
parent 2597 a745e942a666
child 2599 4a54e3221729
child 2602 4d1dec983a8b
Add another backup method to mirror creation
Extensions/MailItemExtensions.cs
     1.1 --- a/Extensions/MailItemExtensions.cs	Wed Mar 13 12:05:27 2019 +0100
     1.2 +++ b/Extensions/MailItemExtensions.cs	Wed Mar 13 13:50:02 2019 +0100
     1.3 @@ -367,214 +367,228 @@
     1.4              Outlook.MailItem mirror = null;
     1.5              Outlook.Folder folder = omi.GetMirrorFolder();
     1.6  
     1.7 -            /* If S/MIME is enabled by default, the mirror creation by new mail item fails during the
     1.8 -             * Save() method. 
     1.9 -             */
    1.10 -            if ((Globals.ThisAddIn.OutlookOptions.IsSMIMEEnabled == false) &&
    1.11 -                (omi.GetIsSMIMEEnabled() == false))
    1.12 +            try
    1.13              {
    1.14 +                Log.Verbose("CreateMirrorOMI: Creating by new mail item.");
    1.15 +
    1.16 +                // Try to create the new mail item directly in the pEp store
    1.17 +                Outlook.Application application = null;
    1.18                  try
    1.19                  {
    1.20 -                    Log.Verbose("CreateMirrorOMI: Creating by new mail item.");
    1.21 -
    1.22                      mirror = (Outlook.MailItem)folder.Items.Add(Outlook.OlItemType.olMailItem);
    1.23 -                    mirror.UnRead = false;
    1.24 -
    1.25 -                    // Set received and sent time
    1.26 -                    try
    1.27 +                }
    1.28 +                catch (Exception ex)
    1.29 +                {
    1.30 +                    // If this fails, log the error and try to create the item with backup method
    1.31 +                    Log.Warning("CreateMirrorOMI: Error creating mirror via Items.ItemAdd. " + ex.ToString());
    1.32 +
    1.33 +                    // If backup fails, let error get thrown out to outer catch
    1.34 +                    application = Globals.ThisAddIn.Application;
    1.35 +                    mirror = application.CreateItem(Outlook.OlItemType.olMailItem);
    1.36 +                    Log.Verbose("CreateMirrorOMI: mail item successfully created via backup method 1.");
    1.37 +                }
    1.38 +                finally
    1.39 +                {
    1.40 +                    application = null;
    1.41 +                }
    1.42 +
    1.43 +                // Set the mirror as read
    1.44 +                mirror.UnRead = false;
    1.45 +
    1.46 +                try
    1.47 +                {
    1.48 +                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagMessageDeliveryTime, omi.ReceivedTime.ToUniversalTime());
    1.49 +                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagClientSubmitTime, omi.SentOn.ToUniversalTime());
    1.50 +                }
    1.51 +                catch (Exception ex)
    1.52 +                {
    1.53 +                    Log.Verbose("CreateMirrorOMI: Failed to set received and sent time. " + ex.ToString());
    1.54 +                    throw;
    1.55 +                }
    1.56 +
    1.57 +                // Attempt to set sender information
    1.58 +                try
    1.59 +                {
    1.60 +                    mirror.Sender = omi.Sender;
    1.61 +                }
    1.62 +                catch (Exception ex)
    1.63 +                {
    1.64 +                    Log.Verbose("CreateMirrorOMI: Failed to set sender directly. " + ex.ToString());
    1.65 +                }
    1.66 +
    1.67 +                try
    1.68 +                {
    1.69 +                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagSenderName, omi.SenderName);
    1.70 +                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagSenderEmailAddress, omi.SenderEmailAddress);
    1.71 +
    1.72 +                    // Entry ID is needed to resolve the sender so a reply is possible without having to re-enter address, this is last in case it fails
    1.73 +                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagSenderEntryId, MapiHelper.GetProperty(omi, MapiProperty.PidTagSenderEntryId));
    1.74 +                }
    1.75 +                catch (Exception ex)
    1.76 +                {
    1.77 +                    Log.Verbose("CreateMirrorOMI: Failed to set sender through MAPI properties. " + ex.ToString());
    1.78 +                    throw;
    1.79 +                }
    1.80 +
    1.81 +                try
    1.82 +                {
    1.83 +                    mirror.SendUsingAccount = omi.SendUsingAccount;
    1.84 +                }
    1.85 +                catch (Exception ex)
    1.86 +                {
    1.87 +                    Log.Verbose("CreateMirrorOMI: Failed to set SendUsingAccount. " + ex.ToString());
    1.88 +                }
    1.89 +
    1.90 +                // Set flags
    1.91 +                messageFlags = (System.Int32)MapiHelper.GetProperty(mirror, MapiProperty.PidTagMessageFlags);
    1.92 +                messageFlags &= ~((System.Int32)MapiPropertyValue.EnumPidTagMessageFlags.mfUnsent);  // Clear UNSENT flag -- must be done before save
    1.93 +                messageFlags |= ((System.Int32)MapiPropertyValue.EnumPidTagMessageFlags.mfRead);     // Mark as read
    1.94 +                try
    1.95 +                {
    1.96 +                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagMessageFlags, messageFlags);
    1.97 +                }
    1.98 +                catch (Exception ex)
    1.99 +                {
   1.100 +                    Log.Verbose("CreateMirrorOMI: Failed to set message flags. " + ex.ToString());
   1.101 +                }
   1.102 +
   1.103 +                // Conversation information
   1.104 +                try
   1.105 +                {
   1.106 +                    /* Note: PidTagConversationId cannot be set even through the MAPI accessor.
   1.107 +                     * This is by design since this property is computed automatically from other properties.
   1.108 +                     * See: https://msdn.microsoft.com/en-us/library/ee204279.aspx
   1.109 +                     */
   1.110 +
   1.111 +                    str = omi.ConversationIndex;
   1.112 +                    bytes = MapiHelper.StringToPtypBinary(str);
   1.113 +                    if (bytes?.Length > 0)
   1.114                      {
   1.115 -                        MapiHelper.SetProperty(mirror, MapiProperty.PidTagMessageDeliveryTime, omi.ReceivedTime.ToUniversalTime());
   1.116 -                        MapiHelper.SetProperty(mirror, MapiProperty.PidTagClientSubmitTime, omi.SentOn.ToUniversalTime());
   1.117 +                        MapiHelper.SetProperty(mirror, MapiProperty.PidTagConversationIndex, bytes);
   1.118                      }
   1.119 -                    catch (Exception ex)
   1.120 +
   1.121 +                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagConversationIndexTracking, true);
   1.122 +                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagConversationTopic, omi.ConversationTopic);
   1.123 +                }
   1.124 +                catch (Exception ex)
   1.125 +                {
   1.126 +                    Log.Verbose("CreateMirrorOMI: Failed to set conversation information. " + ex.ToString());
   1.127 +                }
   1.128 +
   1.129 +                // Remove S/MIME flags if necessary
   1.130 +                mirror.RemoveSMIMEFlags();
   1.131 +
   1.132 +                mirror.To = omi.To;
   1.133 +                mirror.CC = omi.CC;
   1.134 +                mirror.BCC = omi.BCC;
   1.135 +                mirror.Subject = omi.Subject;
   1.136 +                mirror.Body = string.Empty;
   1.137 +                mirror.Save();
   1.138 +
   1.139 +                /* Set all received-by information
   1.140 +                 * 
   1.141 +                 * This must be stored as a user-property because settings MAPI properties such as "PR_RECEIVED_BY_EMAIL_ADDRESS"
   1.142 +                 * is not supported by Outlook. The user-properties are named the same as the MAPI property for simplicity.
   1.143 +                 * 
   1.144 +                 * In most situations the received-by information will not be needed.
   1.145 +                 * Decryption for example uses the recipients/identities in the original mail item itself.
   1.146 +                 * However, the GetMyIdentity(omi) method requires this information in some cases:
   1.147 +                 *  • The true 'myself' identity of a mail item is not an account registerd in Outlook. This can happen
   1.148 +                 *    using aliases or when forwarding emails from another account.
   1.149 +                 *  • This is primarily needed when displaying mirrors themselves then opening the handshake dialog.
   1.150 +                 */
   1.151 +                try
   1.152 +                {
   1.153 +                    /* Get the "received by" email address. In case this returns an internal X500 Exchange address ("/O=DOMAIN/OU=EXCHANGE ADMINISTRATIVE GROUP..."),
   1.154 +                     * compare it with the recipients' addresses and take the primary SMTP address.
   1.155 +                     */
   1.156 +                    string email = MapiHelper.GetProperty(omi, MapiProperty.PidTagReceivedByEmailAddress) as string;
   1.157 +                    if (email.StartsWith("/O"))
   1.158                      {
   1.159 -                        Log.Verbose("CreateMirrorOMI: Failed to set received and sent time. " + ex.ToString());
   1.160 -                        throw;
   1.161 -                    }
   1.162 -
   1.163 -                    // Attempt to set sender information
   1.164 -                    try
   1.165 -                    {
   1.166 -                        mirror.Sender = omi.Sender;
   1.167 -                    }
   1.168 -                    catch (Exception ex)
   1.169 -                    {
   1.170 -                        Log.Verbose("CreateMirrorOMI: Failed to set sender directly. " + ex.ToString());
   1.171 -                    }
   1.172 -
   1.173 -                    try
   1.174 -                    {
   1.175 -                        MapiHelper.SetProperty(mirror, MapiProperty.PidTagSenderName, omi.SenderName);
   1.176 -                        MapiHelper.SetProperty(mirror, MapiProperty.PidTagSenderEmailAddress, omi.SenderEmailAddress);
   1.177 -
   1.178 -                        // Entry ID is needed to resolve the sender so a reply is possible without having to re-enter address, this is last in case it fails
   1.179 -                        MapiHelper.SetProperty(mirror, MapiProperty.PidTagSenderEntryId, MapiHelper.GetProperty(omi, MapiProperty.PidTagSenderEntryId));
   1.180 -                    }
   1.181 -                    catch (Exception ex)
   1.182 -                    {
   1.183 -                        Log.Verbose("CreateMirrorOMI: Failed to set sender through MAPI properties. " + ex.ToString());
   1.184 -                        throw;
   1.185 -                    }
   1.186 -
   1.187 -                    try
   1.188 -                    {
   1.189 -                        mirror.SendUsingAccount = omi.SendUsingAccount;
   1.190 -                    }
   1.191 -                    catch (Exception ex)
   1.192 -                    {
   1.193 -                        Log.Verbose("CreateMirrorOMI: Failed to set SendUsingAccount. " + ex.ToString());
   1.194 -                    }
   1.195 -
   1.196 -                    // Set flags
   1.197 -                    messageFlags = (System.Int32)MapiHelper.GetProperty(mirror, MapiProperty.PidTagMessageFlags);
   1.198 -                    messageFlags &= ~((System.Int32)MapiPropertyValue.EnumPidTagMessageFlags.mfUnsent);  // Clear UNSENT flag -- must be done before save
   1.199 -                    messageFlags |= ((System.Int32)MapiPropertyValue.EnumPidTagMessageFlags.mfRead);     // Mark as read
   1.200 -                    try
   1.201 -                    {
   1.202 -                        MapiHelper.SetProperty(mirror, MapiProperty.PidTagMessageFlags, messageFlags);
   1.203 -                    }
   1.204 -                    catch (Exception ex)
   1.205 -                    {
   1.206 -                        Log.Verbose("CreateMirrorOMI: Failed to set message flags. " + ex.ToString());
   1.207 -                    }
   1.208 -
   1.209 -                    // Conversation information
   1.210 -                    try
   1.211 -                    {
   1.212 -                        /* Note: PidTagConversationId cannot be set even through the MAPI accessor.
   1.213 -                         * This is by design since this property is computed automatically from other properties.
   1.214 -                         * See: https://msdn.microsoft.com/en-us/library/ee204279.aspx
   1.215 -                         */
   1.216 -
   1.217 -                        str = omi.ConversationIndex;
   1.218 -                        bytes = MapiHelper.StringToPtypBinary(str);
   1.219 -                        if (bytes?.Length > 0)
   1.220 +                        Outlook.Recipients recipients = null;
   1.221 +                        Outlook.Recipient recipient = null;
   1.222 +                        Outlook.AddressEntry addressEntry = null;
   1.223 +                        Outlook.ExchangeUser exchangeUser = null;
   1.224 +
   1.225 +                        try
   1.226                          {
   1.227 -                            MapiHelper.SetProperty(mirror, MapiProperty.PidTagConversationIndex, bytes);
   1.228 -                        }
   1.229 -
   1.230 -                        MapiHelper.SetProperty(mirror, MapiProperty.PidTagConversationIndexTracking, true);
   1.231 -                        MapiHelper.SetProperty(mirror, MapiProperty.PidTagConversationTopic, omi.ConversationTopic);
   1.232 -                    }
   1.233 -                    catch (Exception ex)
   1.234 -                    {
   1.235 -                        Log.Verbose("CreateMirrorOMI: Failed to set conversation information. " + ex.ToString());
   1.236 -                    }
   1.237 -
   1.238 -                    // Remove S/MIME flags if necessary
   1.239 -                    mirror.RemoveSMIMEFlags();
   1.240 -
   1.241 -                    mirror.To = omi.To;
   1.242 -                    mirror.CC = omi.CC;
   1.243 -                    mirror.BCC = omi.BCC;
   1.244 -                    mirror.Subject = omi.Subject;
   1.245 -                    mirror.Body = string.Empty;
   1.246 -                    mirror.Save();
   1.247 -
   1.248 -                    /* Set all received-by information
   1.249 -                     * 
   1.250 -                     * This must be stored as a user-property because settings MAPI properties such as "PR_RECEIVED_BY_EMAIL_ADDRESS"
   1.251 -                     * is not supported by Outlook. The user-properties are named the same as the MAPI property for simplicity.
   1.252 -                     * 
   1.253 -                     * In most situations the received-by information will not be needed.
   1.254 -                     * Decryption for example uses the recipients/identities in the original mail item itself.
   1.255 -                     * However, the GetMyIdentity(omi) method requires this information in some cases:
   1.256 -                     *  • The true 'myself' identity of a mail item is not an account registerd in Outlook. This can happen
   1.257 -                     *    using aliases or when forwarding emails from another account.
   1.258 -                     *  • This is primarily needed when displaying mirrors themselves then opening the handshake dialog.
   1.259 -                     */
   1.260 -                    try
   1.261 -                    {
   1.262 -                        /* Get the "received by" email address. In case this returns an internal X500 Exchange address ("/O=DOMAIN/OU=EXCHANGE ADMINISTRATIVE GROUP..."),
   1.263 -                         * compare it with the recipients' addresses and take the primary SMTP address.
   1.264 -                         */
   1.265 -                        string email = MapiHelper.GetProperty(omi, MapiProperty.PidTagReceivedByEmailAddress) as string;
   1.266 -                        if (email.StartsWith("/O"))
   1.267 -                        {
   1.268 -                            Outlook.Recipients recipients = null;
   1.269 -                            Outlook.Recipient recipient = null;
   1.270 -                            Outlook.AddressEntry addressEntry = null;
   1.271 -                            Outlook.ExchangeUser exchangeUser = null;
   1.272 -
   1.273 -                            try
   1.274 +                            recipients = omi.Recipients;
   1.275 +
   1.276 +                            for (int i = 1; i <= recipients.Count; i++)
   1.277                              {
   1.278 -                                recipients = omi.Recipients;
   1.279 -
   1.280 -                                for (int i = 1; i <= recipients.Count; i++)
   1.281 +                                recipient = recipients[i];
   1.282 +                                addressEntry = recipient?.AddressEntry;
   1.283 +                                exchangeUser = addressEntry?.GetExchangeUser();
   1.284 +
   1.285 +                                if (email.ToUpperInvariant().Equals(exchangeUser?.Address?.ToUpperInvariant()))
   1.286                                  {
   1.287 -                                    recipient = recipients[i];
   1.288 -                                    addressEntry = recipient?.AddressEntry;
   1.289 -                                    exchangeUser = addressEntry?.GetExchangeUser();
   1.290 -
   1.291 -                                    if (email.ToUpperInvariant().Equals(exchangeUser?.Address?.ToUpperInvariant()))
   1.292 -                                    {
   1.293 -                                        email = exchangeUser?.PrimarySmtpAddress;
   1.294 -                                        break;
   1.295 -                                    }
   1.296 -
   1.297 -                                    recipient = null;
   1.298 -                                    addressEntry = null;
   1.299 -                                    exchangeUser = null;
   1.300 +                                    email = exchangeUser?.PrimarySmtpAddress;
   1.301 +                                    break;
   1.302                                  }
   1.303 -                            }
   1.304 -                            catch (Exception ex)
   1.305 -                            {
   1.306 -                                Log.Error("CreateMirrorOMI: Error getting ReceivedByEmailAddress. " + ex.ToString());
   1.307 -                            }
   1.308 -                            finally
   1.309 -                            {
   1.310 -                                recipients = null;
   1.311 +
   1.312                                  recipient = null;
   1.313                                  addressEntry = null;
   1.314                                  exchangeUser = null;
   1.315                              }
   1.316                          }
   1.317 -                        mirror.SetUserProperty(MapiProperty.PidTagReceivedByEmailAddress.DaslName, email,
   1.318 -                                            Outlook.OlUserPropertyType.olText);
   1.319 -                        mirror.SetUserProperty(MapiProperty.PidTagReceivedByName.DaslName,
   1.320 -                                            MapiHelper.GetProperty(omi, MapiProperty.PidTagReceivedByName),
   1.321 -                                            Outlook.OlUserPropertyType.olText);
   1.322 +                        catch (Exception ex)
   1.323 +                        {
   1.324 +                            Log.Error("CreateMirrorOMI: Error getting ReceivedByEmailAddress. " + ex.ToString());
   1.325 +                        }
   1.326 +                        finally
   1.327 +                        {
   1.328 +                            recipients = null;
   1.329 +                            recipient = null;
   1.330 +                            addressEntry = null;
   1.331 +                            exchangeUser = null;
   1.332 +                        }
   1.333                      }
   1.334 -                    catch (Exception ex)
   1.335 -                    {
   1.336 -                        Log.Verbose("CreateMirrorOMI: Failed to set received-by information. " + ex.ToString());
   1.337 -                    }
   1.338 -
   1.339 -                    // Mark the mail item as a mirror
   1.340 -                    mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_IS_MIRROR, true, Outlook.OlUserPropertyType.olYesNo);
   1.341 -
   1.342 -                    /* Set the incoming status of the new mail item.
   1.343 -                     * This is necessary because manually setting the PR_RECEIVED_BY_ENTRYID fails if called by user code.
   1.344 -                     * PR_RECEIVED_BY_ENTRYID is only set when copying the original mail item.
   1.345 -                     */
   1.346 -                    if (omi.GetIsIncoming())
   1.347 -                    {
   1.348 -                        mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_IS_INCOMING, true, Outlook.OlUserPropertyType.olYesNo);
   1.349 -                    }
   1.350 -                    else
   1.351 -                    {
   1.352 -                        mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_IS_INCOMING, false, Outlook.OlUserPropertyType.olYesNo);
   1.353 -                    }
   1.354 -
   1.355 -                    // Add the original EntryID or the messageId if the latter has been passed
   1.356 -                    mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_ORIG_ENTRY_ID, messageId ?? omi.EntryID);
   1.357 -                    mirror.Save();
   1.358 -
   1.359 -                    // Move the mirror copy to the correct folder
   1.360 -                    // This is needed as some account-types/office versions will still create a mail item in the default folder
   1.361 -                    // even if folder.Items.Add is used to specify a location.
   1.362 -                    // WARNING: this creates a new mail item that will no longer be referenced here!!
   1.363 -                    mirror.Move(folder);
   1.364 -                    created = true;
   1.365 +                    mirror.SetUserProperty(MapiProperty.PidTagReceivedByEmailAddress.DaslName, email,
   1.366 +                                        Outlook.OlUserPropertyType.olText);
   1.367 +                    mirror.SetUserProperty(MapiProperty.PidTagReceivedByName.DaslName,
   1.368 +                                        MapiHelper.GetProperty(omi, MapiProperty.PidTagReceivedByName),
   1.369 +                                        Outlook.OlUserPropertyType.olText);
   1.370                  }
   1.371                  catch (Exception ex)
   1.372                  {
   1.373 -                    Log.Verbose("CreateMirrorOMI: Creating new mail item failed. " + ex.ToString());
   1.374 -                    mirror.PermanentlyDelete();
   1.375 -                    mirror = null;
   1.376 +                    Log.Verbose("CreateMirrorOMI: Failed to set received-by information. " + ex.ToString());
   1.377                  }
   1.378 +
   1.379 +                // Mark the mail item as a mirror
   1.380 +                mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_IS_MIRROR, true, Outlook.OlUserPropertyType.olYesNo);
   1.381 +
   1.382 +                /* Set the incoming status of the new mail item.
   1.383 +                 * This is necessary because manually setting the PR_RECEIVED_BY_ENTRYID fails if called by user code.
   1.384 +                 * PR_RECEIVED_BY_ENTRYID is only set when copying the original mail item.
   1.385 +                 */
   1.386 +                if (omi.GetIsIncoming())
   1.387 +                {
   1.388 +                    mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_IS_INCOMING, true, Outlook.OlUserPropertyType.olYesNo);
   1.389 +                }
   1.390 +                else
   1.391 +                {
   1.392 +                    mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_IS_INCOMING, false, Outlook.OlUserPropertyType.olYesNo);
   1.393 +                }
   1.394 +
   1.395 +                // Add the original EntryID or the messageId if the latter has been passed
   1.396 +                mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_ORIG_ENTRY_ID, messageId ?? omi.EntryID);
   1.397 +                mirror.Save();
   1.398 +
   1.399 +                // Move the mirror copy to the correct folder
   1.400 +                // This is needed as some account-types/office versions will still create a mail item in the default folder
   1.401 +                // even if folder.Items.Add is used to specify a location.
   1.402 +                // WARNING: this creates a new mail item that will no longer be referenced here!!
   1.403 +                mirror.Move(folder);
   1.404 +                created = true;
   1.405              }
   1.406 -
   1.407 +            catch (Exception ex)
   1.408 +            {
   1.409 +                Log.Verbose("CreateMirrorOMI: Creating new mail item failed. " + ex.ToString());
   1.410 +                mirror.PermanentlyDelete();
   1.411 +                mirror = null;
   1.412 +            }
   1.413 +
   1.414 +            // Backup method
   1.415              if (created == false)
   1.416              {
   1.417                  try