Invio email con body html da codice vba

Anonimo
2023-09-11T10:29:30+00:00

Salve,

Nell'ufficio dove lavoro, settimanalmente c'è la necessità di creare un foglio Excel dove dobbiamo inserire moltissimi dati e in alcune colonne invece dobbiamo importare dei dati da un altro foglio Excel che ci viene fornito ... tutto questo richiede due ore di tempo ...

Ho pensato quindi di automatizzare mediante codice Visual Basic Application

Abbiamo anche l'esigenza di dover inviare una email con allegato il file Excel creato nel cui corpo dobbiamo inserire una tabella riepilogativa

Ovviamente il codice vba che ho scritto
si occupa anche di creare l'email con il body html in cui inserisce automaticamente la tabella riepilogativa

Il problema è che usando il metodo "send" dell'oggetto "olmail" tutto il corpo dell'email viene inviato correttamente

Invece se utilizzo il metodo display (anteprima di outlook) la tabella riepilogativa perde la formattazione prestabilita

Qualcuno sa darmi qualche dritta per aggirare questo problema?

Ringrazio anticipatamente

Microsoft 365 e Office | Excel | Per il lavoro | Android

Domanda bloccata. Questa domanda è stata eseguita dalla community del supporto tecnico Microsoft. È possibile votare se è utile, ma non è possibile aggiungere commenti o risposte o seguire la domanda.

0 commenti Nessun commento

7 risposte

Ordina per: Più recente
  1. Anonimo
    2023-09-14T16:58:43+00:00

    La tabella di riepilogo nell'email l'avrei voluta come nella prima immagine che ho postato, guardando bene tale immagine si vede chiaramente che il bordo esterno della tabella è doppio, che molte righe hanno i bordi punteggiati e che alcune righe con lo sfondo colorato hanno i bordi non punteggiati, sono questi piccoli dettagli che saltano se uso il metodo .display dell'oggetto objEMail mentre se uso il metodo .send (objEMail.send) non ho l'anteprima ma i destinatari ricevono la tabella esattamente come l'ho impostata nel codice html

    Rinunciando invece a questi piccoli dettagli e impostando tutti i bordi a "solid" nel codice html, il problema con il metodo .display non si presenta

    E' solo una questione estetica alla quale potrei chiudere un occhio ma è normale che mi chiedo il perché

    Per quanto riguarda invece l'iniezione dei valori della tabella nel codice html, io ho usato un approccio diverso, carico in una stringa tutto il codice html e con la funzione Replace di VBA immetto i valori, in questo modo il codice HTML non viene modificato ed è possibile riutilizzarlo sempre

    Tutto sommato il codice che ho scritto per inserire i valori è abbastanza semplice .... riporto qui uno stralcio

    Dim strEMailBody, strTemp As String

    Dim i As Long

    strEMailBody = ActiveWorkbook.Worksheets("HTML E-Mail body

    templates").Range("A1").Text

    For i = 1 To 20

    strTemp = "<VBAInteger>intItem" & CStr(i) & "</VBAInteger>"

    If lDataCount(i) = 0 Then

     strEMailBody = Replace(strEMailBody, strTemp, "-", , , vbTextCompare) 
    
     Else 
    
            strEMailBody = Replace(strEMailBody, strTemp, lDataCount(i), , ,  
    
            vbTextCompare) 
    

    End If

    Next i

    SendEMail strEMailBody, "destinatari", strFullPathFileName , .... bla, bla ,bla ....

    l'array lDataCount(1 To 20) è caricato con dei valori ricavati dallo Sheet che deve essere allegato all'email utilizzando la funzione .CountIf dell'oggetto 'WorksheetFunction'

    L'allegato è depurato da ogni altro Sheet e ovviamente dal codice incapsulato

    I valori delle altre due colonne della tabella di riepilogo vengono semplicemente calcolati in funzione dei valori iniettati, per semplicità ho tolto il calcolo in quanto già da queste poche righe si capisce l'algoritmo che ho utilizzato ...

    Dopo l'istruzione For i=0 può notare i segnaposto nel codice HTML che andranno sostituiti con i valori ....

    Ecco come è memorizzato tutto il codice HTML che ripeto non deve essere modificato

    la ringrazio comunque

    La risposta è stata utile?

    0 commenti Nessun commento
  2. Anonimo
    2023-09-14T15:57:21+00:00

    Ciao Federico,

    La ringrazio per il codice che mi ha postato ma non ho problemi ad inviare email da codice vba, anzi il codice che ho scritto funziona perfettamente e comunque è molto più complesso di quanto lei possa immaginare, considera che è un file Excel (appunto un Workbook) che contiene un modulo VBA (con circa 700 righe di codice VBA) + tre moduli di classe + tre Window procedure che gestiscono gli eventi di tre Window (form);

    Il predetto file Excel contiene lo Sheet vero e proprio in cui vengono inseriti dei dati manualmente (mediamente 350/400 righe di dati) e in funzione di questi dati vengono importati altri dati in tre colonne dello Sheet stesso che ci vengono forniti dall'azienda per cui lavoro (la procedura d'importazione è indipendente dal layout dell'origine dei dati da importare ...)

    Poi sono presenti altri Sheets nascosti che contengono dati "interni" utilizzati dal codice VBA e tra questi anche lo Sheet che contiene appunto il body html dell'email che non deve essere modificato per nessun motivo, l'inserimento dei dati per la tabella riepilogativa avviene iniettando il codice HTML in una variabile stringa e l'inserimento dei dati per la tabella di riepilogo viene effettuata sulla stringa e non nel codice HTML del body delle-mail

    Il codice poi non si limita solo ad importare dati e spedire e-mail esegue un controllo dei dati immessi, individua e corregge automaticamente gli errori ed eventuali dati duplicati ridondanti, in particolare verifica la correttezza dei dati immessi manualmente in alcune colonne che sono dei codici che hanno un ben preciso formato e un ben preciso significato ... (per darle un'idea pensi per esempio al codice fiscale che non è una banale stringa ...)

    Infine il codice esporta / estrapola in un file Excel a parte lo Sheet completo dei dati immessi e importati depurandolo dal codice vba incapsulato; questo viene poi allegato all'email che lo stesso codice VBA genera automaticamente inserendo nel body la tabella riepilogativa formata da 20 righe, 5 colonne e un' head

    Tutto questo funziona alla perfezione il problema è solo la tabella riepilogativa nel body dell'email :

    Se uso direttamente il metodo Send dell'oggetto objEMail (objEMail.Send) la tabella viene disegnata nel body esattamente come prestabilito e i destinatari la ricevono esattamente come ho prestabilito

    Se invece uso il metodo .Display (objEMail.Display), cosa che mi serve perché alle volte ci capita di aggiungere brevi note nel body dell'email, note che è impossibile automatizzare, l'anteprima dell'email altera alcuni attributi dei bordi e degli sfondi delle celle della tabella e i destinatari ricevono la tabella con gli attributi alterati. Non è questo un problema in quanto è solo una questione estetica ma non capisco perché Outlook mi debba cambiare gli attributi di stile della tabella

    Forse con delle immagini riesco a spiegarmi meglio ....

    Con il metodo Send l'invio è automatico e la tabella nel body è ricevuta dai destinatari esattamente come prestabilito:

    Immagine

    Con il metodo Display (che è quello che mi serve ... bla ... bla) l'anteprima altera lo stile della tabella, l'invio deve essere comandato manualmente e i destinatari ricevono la tabella come in figura con gli attributi di stile (soprattutto dei bordi) alterato ....

    Immagine

    .

    La complessità del tuo progetto non mi spaventa e posso assicurarti che ho creato e gestito progetti più grandi e complessi.

    Detto questo, indipendentemente dalle dimensioni o dalla complessità del progetto, dovrebbe essere un compito relativamente semplice trasmettere i dati richiesti, comprese le caratteristiche del formato, al codice di invio e-mail standard.

    Nel caso del codice che ho pubblicato, ciò si ottiene passando l'indirizzo della tabella dati alla funzione RangetoHTML. Il codice originale di questa utile funzione è stato, credo, pubblicato da Dick Kusleika e successivamente aggiornato da Ron de Bruin. Come ho dimostrato, questo approccio crea il corpo formattato richiesto sia per l'email finale ma anche la sua anteprima.

    Niente nella tua spiegazione dettagliata mi suggerisce che non potresti sfruttare un approccio simile. Non vedo motivo per cui, a prescindere dalla complessità o meno della creazione della stringa che rappresenta l'indirizzo dei dati del corpo dell'email, non si dovrebbe riuscire a passare questa stringa alla funzione RangetoHTML e ottenere risultati analoghi a quelli mostrati in l'immagine inclusa nella mia risposta precedente.

    Senza il codice completo e un file di esempio è estremamente difficile spiegare perché tu non riesci a ottenere un'anteprima adeguatamente formattata per la email, ma suggerirei che potrebbe essere più rapido e semplice adottare l'approccio che l'approccio che ho suggerito e che ha funzionato con successo per me in innumerevoli occasioni.

    Naturalmente, è sempre possibile che otterrai comunque risultati deludenti se usi il mio approccio. Tuttavia, non lo saprai se non lo proverai e, anche se ciò accadesse, avrei comunque bisogno di una copia della tua tabella dati per indagare sulla questione.

    Per la completezza, creando una tabella simile a la tua, e utilizzando il mio codice, ottengo come anteprima :

    [![Immagine](https://learn-attachment.microsoft.com/api/attachments/a190c0fe-edec-42ec-890a-9e7abfdb5e11?platform=QnA "filestore.community.support.microsoft.com")   
    

    .

    e l'email che ho ricevuto era:

    [![Immagine](https://learn-attachment.microsoft.com/api/attachments/d86325e3-161a-4216-95eb-3dbfc477a36e?platform=QnA "filestore.community.support.microsoft.com")  
    

    .

    ===

    Regards,

    Norman

    Immagine

    La risposta è stata utile?

    0 commenti Nessun commento
  3. Anonimo
    2023-09-14T14:35:44+00:00

    Ho fatto molte verifiche e la colpa è di Microsoft Outlook, l'anteprima dell'email altera lo stile della tabella e evidentemente invia il body dell'email esattamente come mostrato in anteprima ecco perché il problema si presenta utilizzando il metodo Display dell'oggetto objEMail

    Non è neanche un problema del codice HTML perché se lo copio inserendolo in Notepad e lo salvo con estensione html la tabella riepilogativa viene visualizzata da Microsoft Edge correttamente come prestabilito

    Il metodo Send dell'oggetto objEMail che non passa attraverso l'anteprima di Outlook invia la tabella riepilogativa direttamente e esattamente come prestabilito ecco perché con il metodo Send il problema estetico non si presenta

    Ho fatto un'ulteriore prova per accertarmi che è l'anteprima di Outlook è la causa .. ho verificato che aprendo l'email in outlook inviata direttamente con il metodo send la tabella nuovamente risulta alterata ...

    Domanda : PERCHE' ?

    La risposta è stata utile?

    0 commenti Nessun commento
  4. Anonimo
    2023-09-14T14:20:02+00:00

    La ringrazio per il codice che mi ha postato ma non ho problemi ad inviare email da codice vba, anzi il codice che ho scritto funziona perfettamente e comunque è molto più complesso di quanto lei possa immaginare, considera che è un file Excel (appunto un Workbook) che contiene un modulo VBA (con circa 700 righe di codice VBA) + tre moduli di classe + tre Window procedure che gestiscono gli eventi di tre Window (form);

    Il predetto file Excel contiene lo Sheet vero e proprio in cui vengono inseriti dei dati manualmente (mediamente 350/400 righe di dati) e in funzione di questi dati vengono importati altri dati in tre colonne dello Sheet stesso che ci vengono forniti dall'azienda per cui lavoro (la procedura d'importazione è indipendente dal layout dell'origine dei dati da importare ...)

    Poi sono presenti altri Sheets nascosti che contengono dati "interni" utilizzati dal codice VBA e tra questi anche lo Sheet che contiene appunto il body html dell'email che non deve essere modificato per nessun motivo, l'inserimento dei dati per la tabella riepilogativa avviene iniettando il codice HTML in una variabile stringa e l'inserimento dei dati per la tabella di riepilogo viene effettuata sulla stringa e non nel codice HTML del body delle-mail

    Il codice poi non si limita solo ad importare dati e spedire e-mail esegue un controllo dei dati immessi, individua e corregge automaticamente gli errori ed eventuali dati duplicati ridondanti, in particolare verifica la correttezza dei dati immessi manualmente in alcune colonne che sono dei codici che hanno un ben preciso formato e un ben preciso significato ... (per darle un'idea pensi per esempio al codice fiscale che non è una banale stringa ...)

    Infine il codice esporta / estrapola in un file Excel a parte lo Sheet completo dei dati immessi e importati depurandolo dal codice vba incapsulato; questo viene poi allegato all'email che lo stesso codice VBA genera automaticamente inserendo nel body la tabella riepilogativa formata da 20 righe, 5 colonne e un' head

    Tutto questo funziona alla perfezione il problema è solo la tabella riepilogativa nel body dell'email :

    Se uso direttamente il metodo Send dell'oggetto objEMail (objEMail.Send) la tabella viene disegnata nel body esattamente come prestabilito e i destinatari la ricevono esattamente come ho prestabilito

    Se invece uso il metodo .Display (objEMail.Display), cosa che mi serve perché alle volte ci capita di aggiungere brevi note nel body dell'email, note che è impossibile automatizzare, l'anteprima dell'email altera alcuni attributi dei bordi e degli sfondi delle celle della tabella e i destinatari ricevono la tabella con gli attributi alterati. Non è questo un problema in quanto è solo una questione estetica ma non capisco perché Outlook mi debba cambiare gli attributi di stile della tabella

    Forse con delle immagini riesco a spiegarmi meglio ....

    Con il metodo Send l'invio è automatico e la tabella nel body è ricevuta dai destinatari esattamente come prestabilito:

    Con il metodo Display (che è quello che mi serve ... bla ... bla) l'anteprima altera lo stile della tabella, l'invio deve essere comandato manualmente e i destinatari ricevono la tabella come in figura con gli attributi di stile (soprattutto dei bordi) alterato ....

    Direi che c'è una bella differenza estetica, ribadisco non è iun problema di invio email che viene inviata correttamente con l'allegato ai destinatari prestabiliti il problema è l'alterazione dello stile della tabella che comunque è solo un problema estetico che se non riesco a risolvere l'accetto perché tutto il codice vba che ho scritto funziona perfettamente

    La risposta è stata utile?

    0 commenti Nessun commento
  5. Anonimo
    2023-09-14T10:34:05+00:00

    Ciao Federico,

    Prima di tutto la ringrazio per la sua tempestiva risposta al mio quesito,

    Dunque, posto di seguito il codice (VBA) di invio email ma credo che sia del tutto inutile in quanto si tratta di una procedura standard ( una sub per intenderci) alla quale passo come parametri l'oggetto dell'email, i destinatari per competenza e conoscenza, il percorso completo del file Excel da allegare, la stringa del body dell'email ecc. ecc. ...

    Public Sub SendEMail(ByVal strHTMLMailBody As String, ByVal strEMailAddressees As String, ByVal strEMailAttachment As String, bla bla bla ... )

    Dim objOutlookApp As Object

    Dim objMail As Object

    Set objOutlookApp = CreateObject("Outlook.Application")

    Set objMail = objOutlookApp.CreateItem(olMailItem)

    With objMail

    .To = strEMailAddressees

    .Subject = "Test invio email"

    .Attachments.Add (strEMailAttachment)

    .BodyFormat = olFormatHTML

    .HTMLBody = strHTMLMailBody

    ...

    bla .. bla ..bla ... bla ...

    ...

    .Display

    ' .Send

    End With

    End Sub

    Infatti il mio problema non è l'invio dell'email che viene inviata correttamente ma è la formattazione della tabella riepilogativa nel body dell'email che Outlook altera se utilizzo il metodo display, per esempio l'head della tabella perde il colore dello sfondo impostato (background-color) gli attributi dei bordi non sono quelli che ho impostato ecc. ecc.

    Il body dell'email non è altro che il testo del codice HTML , questo contiene delle variabili di riferimento che per il codice HTML non sono null'altro che testo e che in breve vado a rimpiazzare tramite la funzione Replace di VBA con i valori da includere nella tabella riepilogativa; la sostituzione la eseguo fuori dalla Sub SendEMail(), a questa gli passo come parametro il testo html completo di tutti i valori ...

    Il testo HTM del body dell'email è memorizzato in una cella Excel

    Se dunque nella Sub SendEMail() uso direttamente il metodo .send e non uso il metodo .display la tabella riepilogativa nel body viene inviata correttamente se invece utilizzo il metodo display (quindi l'invio dovrà essere comandato manualmente nell'anteprima dell'email) la tabella riepilogativa subisce un'alterazione,

    Che la causa sia outlook ((della suite Microsoft Office 2021 Professional plus) è evidente ...

    Purtroppo in ufficio utilizziamo outlook per le emails e comunque l'anteprima dell'email è necessaria perché di volta in volta capita di dover aggiungere nel body dell'email qualche breve nota del caso

    Sfortunatamente, non hai incluso né un esempio dei tuoi dati né il codice che usi per passare l'intervallo HTML alla tua funzione.

    Per testare il tuo codice sarà necessario pubblicare tutto il codice rilevante e fornire dei dati di esempio.

    In attesa di un file, privo di dati sensibili, il tipo di codice che solitamente utilizzo è:

    '========>>

    Option Explicit

    '-------->>

    Public Sub Tester()

    Dim WB As Workbook 
    
    Dim SH As Worksheet 
    
    Dim Rng As Range 
    
    Const sFoglio As String = **"Foglio1"                                                             '&lt;&lt;=== Modifica** 
    
    Const sIntervallo As String = **"A1:A24"                                                         '&lt;&lt;=== Modifica** 
    
    Const sDestinatario As String = **"pippoCHIOCCIOLAgmail.com"               '&lt;&lt;=== Modifica** 
    
    Const sOggetto As String = **"Esempio\_Mail\_HTML"                                    '&lt;&lt;=== Modifica** 
    
    Set WB = ThisWorkbook 
    
    Set SH = WB.Sheets(sFoglio) 
    
    Set Rng = SH.Range(sIntervallo) 
    
    Call Invia\_Mail\_HTML(Rng, sDestinatario, sOggetto) 
    

    End Sub

    '-------->>

    Public Sub Invia_Mail_HTML(oRng As Range, sRecipient As String, sSubject As String)

    Dim oOutlook As Object 
    
    Dim oMail As Object 
    
    With Application 
    
        .EnableEvents = False 
    
        .ScreenUpdating = False 
    
    End With 
    
    Set oOutlook = CreateObject("Outlook.Application") 
    
    Set oMail = oOutlook.CreateItem(0) 
    
    On Error Resume Next 
    
    With oMail 
    
        .To = sRecipient 
    
        .CC = "" 
    
        .BCC = "" 
    
        .Subject = sSubject 
    
        .HTMLBody = RangetoHTML(oRng) 
    
        .Display  '\\ .Send 
    
    End With 
    
    On Error GoTo 0 
    
    With Application 
    
        .EnableEvents = True 
    
        .ScreenUpdating = True 
    
    End With 
    
    Set oMail = Nothing 
    
    Set oOutlook = Nothing 
    

    End Sub

    '--------->>

    Public Function RangetoHTML(Rng As Range)

    Dim fso As Object 
    
    Dim ts As Object 
    
    Dim TempFile As String 
    
    Dim TempWB As Workbook 
    
    TempFile = Environ$("temp") & "\" & Format(Now, "dd-mm-yy h-mm-ss") & ".htm" 
    
    'Copy the range and create a new workbook to past the data in 
    
    Rng.Copy 
    
    Set TempWB = Workbooks.Add(1) 
    
    With TempWB.Sheets(1) 
    
        .Cells(1).PasteSpecial Paste:=8 
    
        .Cells(1).PasteSpecial xlPasteValues, , False, False 
    
        .Cells(1).PasteSpecial xlPasteFormats, , False, False 
    
        .Cells(1).Select 
    
        Application.CutCopyMode = False 
    
        On Error Resume Next 
    
        .DrawingObjects.Visible = True 
    
        .DrawingObjects.Delete 
    
        On Error GoTo 0 
    
    End With 
    
    'Publish the sheet to a htm file 
    
    With TempWB.PublishObjects.Add( \_ 
    
         SourceType:=xlSourceRange, \_ 
    
         FileName:=TempFile, \_ 
    
         Sheet:=TempWB.Sheets(1).Name, \_ 
    
         Source:=TempWB.Sheets(1).UsedRange.Address, \_ 
    
         HtmlType:=xlHtmlStatic) 
    
        .Publish (True) 
    
    End With 
    
    'Read all data from the htm file into RangetoHTML 
    
    Set fso = CreateObject("Scripting.FileSystemObject") 
    
    Set ts = fso.GetFile(TempFile).OpenAsTextStream(1, -2) 
    
    RangetoHTML = ts.readall 
    
    ts.Close 
    
    RangetoHTML = Replace(RangetoHTML, "align=center x:publishsource=", \_ 
    
                          "align=left x:publishsource=") 
    
    'Close TempWB 
    
    TempWB.Close savechanges:=False 
    
    'Delete the htm file we used in this function 
    
    Kill TempFile 
    
    Set ts = Nothing 
    
    Set fso = Nothing 
    
    Set TempWB = Nothing 
    

    End Function

    '<<========

    Eseguendo questo codice con un semplice file di prova, io ottengo un anteprima dell'email del seguente genere:

      [![Immagine](https://learn-attachment.microsoft.com/api/attachments/c685483a-31ed-45f0-a96b-b3c78c3cc33e?platform=QnA "filestore.community.support.microsoft.com")
    

    .

    ===

    Regards,

    Norman

    Immagine

    La risposta è stata utile?

    1 persona ha trovato utile questa risposta.
    0 commenti Nessun commento