Ejemplo n.º 1
0
        /// <summary> Esegue gli invii per la PECMailBox passata per parametro. </summary>
        /// <param name="box">PECMailBox in cui cercare i messaggi da spedire.</param>
        public void Process(PECMailBox box, string password)
        {
            FileLogger.Info(_loggerName, string.Format("Avvio ciclo di invio per la casella {0} - {1}", box.Id, box.MailBoxName));

            // Gestisco la duplicazione delle PEC marchiate tali
            GenerateMultiplePecs(box);

            // Recupero da DB l'elenco delle PEC in uscita non ancora spedite (MailDate NULL). Carcio anche le PEC in stato Processing.
            bool          useStatusProcessing = true;
            IList <Int32> mail_ids            = _factory.PECMailFacade.GetOutgoingMails(box.Id, box.Configuration.MaxSendForSession, useStatusProcessing);

            FileLogger.Info(_loggerName, string.Format("Trovate {0} PEC da spedire.", mail_ids.Count));

            // Eseguo un ciclo sulle PEC da spedire fino al numero massimo di PEC gestibili per sessione di lavoro
            int successSendMail = 0;
            int errorSendMail   = 0;
            int counter         = 0;

            for (int index = 0; index < mail_ids.Count && counter < box.Configuration.MaxSendForSession; index++)
            {
                if (_cancelRequest())
                {
                    FileLogger.Info(_loggerName, "Blocco invio PEC per chiusura modulo invocata dall'utente.");
                    return;
                }

                // Avvio watch per verificare quanto ci impiega per singola mail
                //TODO : da mettere in debug mode
                Stopwatch watch = Stopwatch.StartNew();
                PECMail   mail  = MailStoreFacade.Factory.PECMailFacade.GetById(mail_ids[index]);

                if (mail.IsActive != ActiveType.Cast(ActiveType.PECMailActiveType.Active) && mail.IsActive != ActiveType.Cast(ActiveType.PECMailActiveType.Processing))
                {
                    FileLogger.Info(_loggerName, string.Format("Errore in lettura pecMail [{0}]. Lo status doveva essere 1. Possibile aggiornamento dati non previsto.", mail.Id));
                    return;
                }

                MailStoreFacade.Factory.TaskHeaderFacade.ActivatePECTaskProcess(mail);

                mail.IsActive = ActiveType.Cast(ActiveType.PECMailActiveType.Processing);
                _factory.PECMailFacade.Update(ref mail);
                FileLogger.Info(_loggerName, string.Format("Inizio processamento PEC [{0}] per invio. - Item #{1}", mail.Id, counter));

                // Preparo i dati per l'invio
                Guid      guid              = Guid.NewGuid();
                String    fullName          = string.Empty;
                IMail     iMailPec          = null;
                int       i                 = 0;
                Exception lastException     = null;
                String    errorLastSendMail = string.Empty;
                while (iMailPec == null && i < 5)
                {
                    // Salvo solamente gli errori dell'ultimo step esecuitivo
                    StringBuilder errorMessage = new StringBuilder();

                    try
                    {
                        iMailPec = PrepareEmlData(mail, guid, ref fullName, ref errorMessage);
                        if (iMailPec == null)
                        {
                            FileLogger.Error(_loggerName, string.Format("Tentativo di creazione eml {0}/5 saltato per massimo numero di elementi in Temp raggiunto per la PEC [{1}]", i + 1, mail.Id));
                        }
                    }
                    catch (Exception ex)
                    {
                        string errMsg = string.Format("Errore in fase di inserimento in Biblos per invio della PEC [{0}] - Tentativo {1}/5", mail.Id, i + 1);
                        errorMessage.Append(errMsg);
                        FileLogger.Error(_loggerName, errMsg, ex);
                        lastException = ex;

                        if (_cancelRequest())
                        {
                            String message = "Blocco invio PEC per chiusura modulo invocata dall'utente a causa di errore in fase di preparazione dati EML.";
                            errorMessage.Append(message);
                            _factory.PECMailLogFacade.Warning(ref mail, message);
                            FileLogger.Info(_loggerName, message);
                            return;
                        }

                        Thread.Sleep(1000 * 30);
                    }
                    finally
                    {
                        errorLastSendMail = errorMessage.ToString();
                        i++;
                    }
                }

                // Ho eseguito operazioni importanti per cui libero la memoria
                GC.Collect();

                // Se a questo punto non sono riuscito ad ottenere un oggetto iMail significa che ci sono problemi su Biblos o su FileSystem,
                // quindi notifico, blocco e procedo oltre
                if (iMailPec == null)
                {
                    String errorResult = string.Format("La PEC {0} della casella {1} - {2} non è stata correttamente inserita in Biblos per 5 volte. La PEC non è stata inviata ed è stata disattivata (isActive = 255) e dovrà essere riattivata previa verifica dell'errore.", mail.Id, box.Id, box.MailBoxName);
                    mail.IsActive = ActiveType.Cast(ActiveType.PECMailActiveType.Error);
                    _factory.PECMailFacade.UpdateOnly(ref mail);
                    _factory.PECMailLogFacade.Error(ref mail, string.Concat(errorResult, errorLastSendMail));
                    MailStoreFacade.SetPECMailTaskError(mail);
                    throw new Exception(errorResult, lastException);
                }

                // Se sono qui significa che tutti i dati su Biblos sono stati memorizzati
                // Spedisco la PEC via SMTP
                try
                {
                    if (SendMail(box, iMailPec, mail, guid, password))
                    {
                        // Se sono riuscito ad inviare allora salvo su Server via IMAP
                        successSendMail++;

                        try
                        {
                            //Aggiorno l'attributo MailDate per l'archivio di conservazione
                            BiblosDocumentInfo mainInfo = BiblosDocumentInfo.GetDocuments(mail.Location.ConservationServer, mail.IDMailContent).SingleOrDefault();
                            FileLogger.Info(_loggerName, "Tentativo di aggiornare attributo MailDate");
                            mainInfo.AddAttribute("MailDate", mail.MailDate.Value.ToString(new CultureInfo("it-IT")
                            {
                                DateTimeFormat = new DateTimeFormatInfo {
                                    ShortDatePattern = "dd/MM/yyyy"
                                }
                            }), true);
                            mainInfo.Update("BibloDS");
                            FileLogger.Info(_loggerName, string.Format("Attributi della PEC con ID {0} aggiornati.", mail.Id));
                        }
                        catch (Exception ex)
                        {
                            _factory.PECMailLogFacade.Error(ref mail, string.Format("Errore in fase di aggiornamento attributi conservazione: {0}", ex.Message));
                            _sendMessage(string.Format("Errore in fase di aggiornamento attributi conservazione: {0} - Stacktrace: {1}", ex.Message, _fullStacktrace(ex)));
                        }

                        try
                        {
                            mail.IsActive = ActiveType.Cast(ActiveType.PECMailActiveType.Active);
                            _factory.PECMailFacade.UpdateOnly(ref mail);

                            SaveMail(box, iMailPec, mail, password);
                        }
                        catch (Exception ex)
                        {
                            _factory.PECMailLogFacade.Error(ref mail, string.Format("Errore in fase di salvataggio mail su IMAP: {0}", ex.Message));
                            _sendMessage(string.Format("Errore in fase di salvataggio mail su IMAP: {0} - Stacktrace: {1}", ex.Message, _fullStacktrace(ex)));
                        }

                        MailStoreFacade.CompletePECMailTask(mail);
                        // Pulisco eventuali dati sporchi rimanenti
                        CleanEmlData(mail.Id, _parameters.TempFolder);
                    }
                    else
                    {
                        errorSendMail++;
                    }
                }
                catch (Exception ex)
                {
                    _factory.PECMailLogFacade.Error(ref mail, string.Format("Errore in fase di invio mail: {0}", ex.Message));
                    _sendMessage(string.Format("Errore in fase di invio mail: {0} - Stacktrace: {1}", ex.Message, _fullStacktrace(ex)));
                    MailStoreFacade.SetPECMailTaskError(mail);
                }

                // Fermo il Watch e registro il LOG
                watch.Stop();
                FileLogger.Info(_loggerName, string.Format("Fine processamento PEC [{0}] per invio. Gestione avvenuta in {1} millisecondi. Item #{2}", mail.Id, watch.ElapsedMilliseconds, counter));

                // Procedo con la PEC successiva
                counter++;

                // Fermo il thread per non sovraccaricare troppo i sistemi
                if (_parameters.SendSleep > 0)
                {
                    Thread.Sleep(1000 * _parameters.SendSleep);
                }
            }
            if (successSendMail > 0)
            {
                _factory.PECMailboxLogFacade.InsertLog(ref box, string.Format("PEC Inviate {0} con successo", successSendMail), PECMailBoxLogFacade.PecMailBoxLogType.Sent);
            }
            if (errorSendMail > 0)
            {
                _factory.PECMailboxLogFacade.InsertLog(ref box, string.Format("Ci sono {0} PecMail da controllare", errorSendMail), PECMailBoxLogFacade.PecMailBoxLogType.SentError);
            }

            FileLogger.Info(_loggerName, string.Format("Fine ciclo di invio per la casella {0} - {1}", box.Id, box.MailBoxName));
        }
Ejemplo n.º 2
0
        /// <summary> Spedisce l'email. </summary>
        /// <param name="mailbox"> MailBox da dove spedire l'email. </param>
        /// <param name="email"> Email da spedire. </param>
        /// <param name="pecMail"> PEC da inviare </param>
        /// <param name="guid"> Guid della mail</param>
        public bool SendMail(PECMailBox mailbox, IMail email, PECMail pecMail, Guid guid, string password)
        {
            // In caso di modalità DEBUG modifico i destinatari con quello di default:
            if (_parameters.DebugModeEnabled)
            {
                // Creo una nuova mail alla quale aggiungo come allegato la mail originale
                MailBuilder debugBuilder = new MailBuilder();
                debugBuilder.From.Add(email.From.First());

                debugBuilder.Subject = string.Format("Inoltro messaggio per DEBUG -> {0}", email.Subject);

                // Crea il corpo del messaggio di default (non è richiesto dall'Interoperabilità) o lo legge da base dati, se indicato
                debugBuilder.Text = "In allegato la mail che sarebbe stata spedita.";

                // Aggiungo il destinatario di debug
                debugBuilder.To.Add(new MailBox(_parameters.PecOutAddressDebugMode, "DEBUG ADDRESS"));

                // Aggiungo la mail come allegatos
                debugBuilder.AddAttachment(email);

                // Sostituisco item con il debugMail
                email = debugBuilder.Create();

                FileLogger.Info(_loggerName, string.Format("Modificato l'indirizzo di invio della PEC con l'indirizzo {0}.", _parameters.PecOutAddressDebugMode));
            }

            // Eseguo in modo atomico il blocco di invio
            int  i    = 0;
            bool sent = false;
            ISendMessageResult sendResult    = null;
            Exception          lastException = null;

            while (!sent && i < 5)
            {
                try
                {
                    using (Smtp smtp = new Smtp())
                    {
                        smtp.ServerCertificateValidate += ServerCertificateValidateHandler;

                        // Utilizzo connessione SSL
                        if (mailbox.OutgoingServerUseSsl.HasValue && mailbox.OutgoingServerUseSsl.Value)
                        {
                            smtp.SSLConfiguration.EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls12;
                            smtp.ConnectSSL(mailbox.OutgoingServerName, mailbox.OutgoingServerPort.HasValue ? mailbox.OutgoingServerPort.Value : 465);
                        }
                        else
                        {
                            smtp.Connect(mailbox.OutgoingServerName, mailbox.OutgoingServerPort.HasValue ? mailbox.OutgoingServerPort.Value : 25);
                        }

                        // Utilizzo autenticazione
                        if (!string.IsNullOrEmpty(mailbox.Username) && !string.IsNullOrEmpty(password))
                        {
                            smtp.UseBestLogin(mailbox.Username, password);
                        }

                        sendResult = smtp.SendMessage(email);
                        sent       = (sendResult.Status == SendMessageStatus.Success);
                        if (!sent)
                        {
                            string errors = string.Empty;
                            if (sendResult.GeneralErrors != null && sendResult.GeneralErrors.Any())
                            {
                                errors = string.Join(", ", sendResult.GeneralErrors
                                                     .Select(f => string.Concat("Code: ", f.Code, " - EnhancedStatusCode: ", f.EnhancedStatusCode, " - Message: ", f.Message, " - Status : ", f.Status)));
                            }
                            FileLogger.Error(_loggerName, string.Format("Errore in spedizione PEC {0} / casella {1} - {2}. Stato spedizione: {3} - Errori:{4}.", pecMail.Id, mailbox.Id, mailbox.MailBoxName, sendResult.Status, errors));
                        }
                        smtp.Close(false);
                    }

                    if (!sent)
                    {
                        continue;
                    }

                    // Aggiorno immediatamente la PEC come spedita in modo da non avere dubbi che la PEC sia stata davvero spedita
                    pecMail.MailDate = DateTime.Now;
                    pecMail.XRiferimentoMessageID = string.Format("<{0}>", guid);
                    _factory.PECMailFacade.UpdateOnly(ref pecMail);
                    Protocol currentProtocol = _factory.PECMailFacade.GetProtocol(pecMail);
                    if (currentProtocol != null && (short)ProtocolKind.FatturePA == currentProtocol.IdProtocolKind)
                    {
                        currentProtocol.IdStatus = (int)ProtocolStatusId.PAInvoiceSent;
                        _factory.ProtocolFacade.UpdateOnly(ref currentProtocol);
                    }
                }
                catch (Exception ex)
                {
                    lastException = ex;
                    // Se mi trovo in questo status è avvenuto un errore in fase di spedizione, per cui posso riprocedere ad inviare
                    FileLogger.Error(_loggerName, string.Format("Non è stato possibile inviare la PEC {0} / casella {1} - {2} per un probabile errore di rete o di server PEC. La procedura verrà ritentata. - Tentativo {3}/5", pecMail.Id, mailbox.Id, mailbox.MailBoxName, i + 1), ex);
                    // Attendo 1 minuto prima di riprovare
#if !DEBUG
                    Thread.Sleep(1000 * 30);
#endif
                }
                finally
                {
                    // Procedo
                    i++;
                }
            }

            // Se dopo 5 tentativi ancora non ha ricevuto conferma di spedizione allora invio una mail e blocco l'invio
            if (sent)
            {
                _factory.PECMailboxLogFacade.SentMail(ref pecMail);
                return(true);
            }
            // Errori
            String errorMessages = string.Format("Errori di invio:{0}", Environment.NewLine);
            errorMessages = sendResult.GeneralErrors.Aggregate(errorMessages, (current, generalError) => current + string.Format("Code:{1} - Message:{2} - Status:{3}{0}", Environment.NewLine, generalError.Code, generalError.Message, generalError.Status));
            _factory.PECMailboxLogFacade.SentErrorMail(ref pecMail, new Exception(errorMessages));

            pecMail.IsActive = ActiveType.Cast(ActiveType.PECMailActiveType.Error);
            _factory.PECMailFacade.UpdateOnly(ref pecMail);
            String errorResult = string.Format("La PEC {0} / casella {1} - {2} non è stata spedita dopo 5 tentativi falliti. \nE' stata pertanto disattivata (isActive = 255) per evitare ulteriori tentativi.", pecMail.Id, mailbox.Id, mailbox.MailBoxName);
            _factory.PECMailLogFacade.Error(ref pecMail, errorResult);
            _factory.PECMailLogFacade.Error(ref pecMail, string.Concat(errorResult, errorMessages));
            MailStoreFacade.SetPECMailTaskError(pecMail);
            throw new Exception(errorResult, lastException);
        }