Newsgroup: it.comp.appl.access
Titolo: salvare mail outlook sul disco fisso in una cartella

Buongiorno a tutti, 
 
Con questo codice invio una mail da access con outlook, è possibile salvare copia del messaggio in un determinato percorso dando un determinato nome alla mail in una cartella del PC?
 
    Dim OutlookApp As Outlook.Application
    Dim MItem As Object
    Dim Recipient As String
    Dim Msg As String, fname As String
 
    On Error Resume Next
 
    Set OutlookApp = New Outlook.Application
    Set MItem = OutlookApp.CreateItem(olMailItem)
    With MItem
        .To = destinatario
        .Subject = Nz(oggetto, "")
        .Body = Nz(Testo, "")
        .Attachments.Add Nz(allegato, "")
        .Activate
        .display
        .Activate
        '.Send
    End With
 
    Set OutlookApp = Nothing


a naso proverei
 
.SaveAs ("c:\tuacartella\tuaMail.eml")
 
 
BFS


anzi senza naso vedi qui va
https://learn.microsoft.com/en-us/office/vba/api/outlook.mailitem.saveas
 
 
 
BFS


ok grazie ho trovato anche un vecchio post del 2019 
https://groups.google.com/g/it.comp.appl.access/c/YiJAQ_N_mxY/m/F611oWkaBwAJ
 
 
il mio problema è però il seguente, apro in anteprima il messaggio creato da vba, l'operatore può modificare tale messaggio scrivendo ulteriore testo e aggiungendo allegati e/o immagini all'interno del corpo della mail, infine clicca il tasto "invia"
 
è in questo momento che ho necessità di salvare il messaggio non prima di aprire l'anteprima altrimenti non ci sarebbero le modifiche dell''operatore
 
fattibile?
 
 
 
 
 
 
 
 
 
 
 
 


ci sono quasi, dopo la sub "inviaMail" che apre in anteprima il messaggio per consentire all'operatore di modificare la mail eseguo una sub di nome "SaveLastSentItem"
il problema è che viene eseguita subito dopo la sub "inviaMail" quindi salva l'ultimo messaggio inviato in outlook che non è quello che l'operatore ha aperto in anteprima
 
è possibile mettere in attesa access e ritornare al codice dopo che l'operatore ha inviato la mail?
 
*** codice ****
 
Public Sub SaveLastSentItem(pathf As String, nomef As String)
 
Dim myItems As Object
Dim savePath As String
 
Set myItems = CreateObject("Outlook.Application").CreateItem(oMailItem)
Set Mail = myItems
 
    Dim oApp As Outlook.Application
    Dim myNameSpace As Outlook.NameSpace
    Dim myFolder As Outlook.Folder
    Dim myNewFolder As Outlook.Folder
    Dim myItem As Outlook.MailItem
    Dim myCopiedItem As Outlook.MailItem
 
 
   Set oApp = New Outlook.Application
 
    Set myNameSpace = oApp.GetNamespace("MAPI")
 
    Set myFolder = myNameSpace.GetDefaultFolder(olFolderSentMail)
 
    Set myItems = myFolder.Items
 
   myItems.Sort ("[SentOn]")
 
    Set myItem = myItems.GetLast
 
 
    savePath = pathf    '## Modify as needed
    savePath = savePath & nomef
 
 
     myItem.SaveAs savePath, OlSaveAsType.olMSG
 
End Sub
 
 
 
 
 
 
 


è nel link che hai inserito la soluzione
RobertoA afferma che prima salva il messaggio per ottenere il suo id
una volta che hai l'id, anche se il messaggio viene modificato e poi 
inviato l'id rimane quello.
 
quindi ti basta andartelo a recuperare e ri-salvarlo nella cartella che 
vuoi.
 
magari posta il codice a cosa fatta che può tornare utile a tutti
BFS
 
 
 


ho provato la riga Debug.print objOutlookMsg.EntryID
ma è vuoto objOutlookMsg.EntryID
 
ho pensato di procedere così, quando l'operatore chiude la schermata per tornare al menù principale si suppone che le mail siano state inviate
non saprei come impedire di uscire da quella form prima che le mail vengano effettivamente inviate (è possibile?)
 
cliccando quindi il pulsante "salva e torna al menù" vado a salvare l'ultimo messaggio inviato in outlook con getlast del mio esempio messaggi precedenti se ne ha inviato solo uno e se ha inviato più mail con un ciclo for eseguo 
N volte getprevious salvando ogni volta i messaggi con:
 
myItem.SaveAs savePath, OlSaveAsType.olMSG
 
spero di essere riuscito a spiegarmi
 


ti sbagli
ho appena provato
 
se aggiungi
 
 
.Save
Debug.Print .EntryID
 
 
il debug nel mio caso mi restituisce
 
0000000003C0152B8C360E40B1F52A54992DA66E24012000
 
che è l'id della mail che posso usare per andarmela a recuperare in ogni 
momento
 
ciao
BFS


ok EntryID era vuoto perchè prima non facevo .save
ma ora ti chiedo, in che modo salvo esattamente quel messaggio avente ID=EntryID?
 
grazie.


non ti piace googolare vedo
 
fonte della funzione  Outlook_OpenEmail
https://www.devhut.net/vba-retrieve-an-outlook-message-item/
 
 
 
sul tuo codice
 
'hai la mail in anteprima e la modifichi come vuoi
.Display (True)
'appena la invii il codice va avanti e ti salva e genera l'id della mail 
modificata
.Save
Debug.Print .EntryID
 
'la funzione del link ti recupera la mail a video:
Outlook_OpenEmail .EntryID
 
 
quindi, nel tuo caso che non ti serve rivederla a video ma semplicemente 
salvarla in altra cartella ti basta modificarla cosi
 
  Set oNameSpace = oOutlook.GetNamespace("MAPI")
     'Find the item, if not found it generates a -
2147221233
 error
     Set oOutlookMsg = oNameSpace.GetItemFromID(sEntryId)
     'Open/Display the item to the user
     oOutlookMsg.saveas "metti qui tuo percorso"...
 
 
 
BFS
 
 
 
 
 


la mail l'ho inviata ed è in posta inviata 
l'ho salvata in una tabella temporanea nel campo di nome IDmail di tipo testo
 
Set myItem = myNameSpace.GetItemFromID(Rs!IDMail)
 
mi da errore: Errore di run-time '-
2147221233
(8004010f)':
Operazione non riuscita. impossibile trovare un offetto.
 
Qualche aiuto?
 
 
 
 


devi modificare la funzione del link!
 
a cui passerai il tuo rs|!idmail
questa:
 
Function Outlook_OpenEmail(ByVal sEntryId As String)
'REF: 
https://docs.microsoft.com/en-us/office/vba/api/outlook.namespace.getitemfromid
 
'    #Const EarlyBind = 1 'Use Early Binding
     #Const EarlyBind = 0    'Use Late Binding
     #If EarlyBind Then
         Dim oOutlook          As Outlook.Application
         Dim oOutlookMsg       As Outlook.MailItem
     #Else
         Dim oOutlook          As Object
         Dim oOutlookMsg       As Object
     #End If
 
     On Error Resume Next
     Set oOutlook = GetObject(, "Outlook.Application")        'Bind to 
existing instance of Outlook
     If Err.Number <> 0 Then        'Could not get instance, so create a 
new one
         Err.Clear
         Set oOutlook = CreateObject("Outlook.Application")
     End If
     On Error GoTo Error_Handler
 
     Set oNameSpace = oOutlook.GetNamespace("MAPI")
     'Find the item, if not found it generates a -
2147221233
 error
     Set oOutlookMsg = oNameSpace.GetItemFromID(sEntryId)
     'Open/Display the item to the user
 
'versione originale tii mostra la mail a video	<<<<<<<<<<<<<<
  '   oOutlookMsg.Display
 
'tu invce vuoi salvarla quindi DEVI MODIFICARLA QUI...<<<<<<<<<
	oOutlookMsg.SaveAs percorso etc etc
 
Error_Handler_Exit:
     On Error Resume Next
     If Not oOutlookMsg Is Nothing Then Set oOutlookMsg = Nothing
     If Not oOutlook Is Nothing Then Set oOutlook = Nothing
     Exit Function
 
Error_Handler:
     If Err.Number = "287" Then
         MsgBox "You clicked No to the Outlook security warning. " & _
                "Rerun the procedure and click Yes to access e-mail " & _
                "addresses to send your message. For more information, " & _
                "see the document at 
http://www.microsoft.com/office
" & _
                "/previous/outlook/downloads/security.asp."
     ElseIf Err.Number = -
2147221233
 Then
         MsgBox "Outlook item not found.", vbInformation + vbOKOnly
     Else
         MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
                "Error Number: " & Err.Number & vbCrLf & _
                "Error Source: Outlook_OpenEmail" & vbCrLf & _
                "Error Description: " & Err.Description & _
                Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
                , vbOKOnly + vbCritical, "An Error has Occurred!"
     End If
     Resume Error_Handler_Exit
End Function
 
 
 
 


sapresti dirmi come modificare questo codice per fargli cercare il messaggio avente EntryID ricevuto come parametro ma nella cartella posta inviata
non so come fare.
 


ho provato aggiungendo le seguenti righe ma nulla da fare 
    Set oNameSpace = oOutlook.GetNamespace("MAPI")
    Set myFolder = oNameSpace.GetDefaultFolder(olFolderSentMail)
    Set myItems = myFolder.Items
    myItems.Sort ("[SentOn]")
 
da sempre errore "Outlook item not found."
 


Help! Questa è la sub che sto provando, la eseguo e da errore alla riga 
Set myItem = myNameSpace.GetItemFromID(EntryID, FolderID)
 
errore di run-time -
2147221233
 (8004010f)
Operazione non riuscita. Impossibile trovare un oggetto.
 
sia entryID che folderID sono correttamente valorizzati, il messaggio in posta inviata c'è 
ma dall'errore sembra che non trova il messaggio, qualcuno può provarlo e scoprire se sul suo pc funziona? grazie.
 
 
***** code ****
Public Sub SalvaMail()
    Dim myItems As Object
    Dim savePath As String
 
    Dim percorso As String
    Dim nomefile As String
    Dim FolderID As String
 
    Dim oApp As Outlook.Application
    Dim myNameSpace As Outlook.NameSpace
    Dim myFolder As Outlook.Folder
    Dim myNewFolder As Outlook.Folder
    Dim myItem As Outlook.MailItem
    Dim myCopiedItem As Outlook.MailItem
    Dim omailitem
    Dim mail
    Dim i
 
    Set myItems = CreateObject("Outlook.Application").CreateItem(omailitem)
    Set mail = myItems
 
 
             'imposto il nome del file
             percorso = "c:\miacartella\"
             nomefile = "messaggio.msg"
 
             Set oApp = New Outlook.Application
 
             Set myNameSpace = oApp.GetNamespace("MAPI")
 
             Set myFolder = myNameSpace.GetDefaultFolder(olFolderSentMail)
 
             'ottengo l'ID della cartella posta inviata 
             FolderID = myFolder.storeId 
 
             Set myItems = myFolder.Items
 
             myItems.Sort ("[SentOn]")
 
 
            Set myItem = myNameSpace.GetItemFromID(Rs!IDMail, FolderID)
 
             savePath = percorso   
             savePath = savePath & nomefile



Se commento la riga di codice
Set myItem = myNameSpace.GetItemFromID(Rs!IDMail, FolderID)
 
ed eseguo la riga di codice
Set myItem = myItems.GetLast
 
Salva l'ultimo messaggio inviato correttamente, lo utilizzerei così ma può accadere che l'operatore invia altre mail dopo aver inviato la mail che mi interessa salvare e quindi quella mail da salvare non è più l'ultima, devo usare quindi questa riga che non vuole saperne di funzionare, o meglio forse funziona ma non trova la mail e quindi da l'errore del mio messaggio precedente.



non ho capito cosa ti schifa di questa funzione, pronta, chiara, funzionante
 
https://www.devhut.net/vba-retrieve-an-outlook-message-item/
 
 
per recuperare una mail dal suo id.
ti basta semplicemente sostituire il .display con .saveAs
 
non capisco perchè complicarsi la vita inutilmente
 
BFS


Ok nel casino dello sviluppo credo di averla provata fra le tante prove fatte ma non pensavo che la soluzione fosse cosi semplice come scrivi, adesso la riprovo.
Grazie per aver rimarcato la cosa.

Il giorno venerdì 4 novembre 2022 alle 07:40:33 UTC+1 BFS ha scritto:

Ecco perché avevo fatto altre prove, la riga di codice 
Set oOutlookMsg = oNameSpace.GetItemFromID(sEntryId)
che riceve come parametro stringa il EntryID --> 
 
00000000862F893433F6804EA5E48276F2CA4F9A070034AD76187591974DBF6C4F76951C873A010000000000000012C64DB6DB1A9D4588144FAB32E0F1DE0000000008CA0000
 
quel codice è stato assegnato al messaggio che mi interessa quando ho fatto .Save in fase di creazione della mail: 
mi restituisce l'errore: Outlook Item Not found ovvero l'errore Err.Number = -
2147221233
 
 
da quell'errore intuisco che tutto funziona ma access non trova il messaggio.
ma il messaggio posso garantire è presente in posta inviata e infatti se uso un altro esempio che preleva l'ultimo messaggio inviato con getlast funziona perfettamente
quello che ipotizzo è che il tuo esempio cerchi di default in una cartella diversa da "posta inviata" e per questo motivo non trova il messaggio?
 
fammi sapere se capisci il motivo.
Grazie.
 
 
 
 
 


da questo articolo 
https://learn.microsoft.com/it-it/office/vba/api/outlook.mailitem.entryid
 
 
cito: 
The Entry ID changes when an item is moved into another store, for example, from your Inbox to a Microsoft Exchange Server public folder, or from one Personal Folders (.pst) file to another .pst file. Solutions should not depend on the EntryID property to be unique unless items will not be moved
 
traduzione: 
L'ID voce cambia quando un elemento viene spostato in un altro archivio, ad esempio, dalla Posta in arrivo a una cartella pubblica di Microsoft Exchange Server o da un file delle cartelle personali (pst) a un altro file pst. Le soluzioni non devono dipendere dalla proprietà EntryID per essere univoca a meno che gli elementi non vengano spostati
 
Quando creo la mail e la salvo con .save ottengo un EntryID che salvo in una tabella temporanea
il mio dubbio è : da come si legge qui sopra quando un messaggio cambia posizione cambia anche entryID, quindi l'EntryID che cerco potrebbe essere diverso perchè una volta inviata la mail questa finisce (ipotizzo) dalla cartella "bozze" o "temp" alla cartella "inviata"? se cosi fosse come recuperare il nuovo EntryID che viene assegnato al messaggio quando va a finire in posta inviata?
 
 


esiste un modo in outlook o con qualche utility di sapere il codice EntryID di un determinato messaggio? in questo modo potrei capire se il codice EntryId che cerco è diverso da quello che è assegnato al messaggio che cerco quando viene spostato in posta inviata.
 
grazie.


Ho scoperto il problema, confermo che EntryID della stessa mail è diverso quando il messaggio viene creato e subito salvato con .Save e quando viene modificato e poi inviato e finisce in posta inviata di outlook
per recuperare il nuovo EntryID ho usato una Sub che applica delle restrizioni agli oggetti items le mail presenti in posta inviata a quel punto ho provato a passare il nuovo EntryID e il codice di BFS funziona perfettamente.
 
per maggiori info sul metodo restrict leggere questo articolo 
https://learn.microsoft.com/en-us/office/vba/api/outlook.items.restrict
 
secondo voi negli oggetti presenti in questo articolo c'è l'oggetto mail destinatario che magari ha un altro nome? io non la vedo.
 
il codice di ricerca è 
 
Public Sub CercaEmail()
    Dim oINS As NameSpace
    Dim Folderinbox As MAPIFolder
    Dim filtered_items As Items
    Dim strFilter As String
    Dim olMail As MailItem
 
    Set oINS = GetNamespace("MAPI")
    Set Folderinbox = oINS.GetDefaultFolder(olFolderSentMail)
 
    strFilter = "@SQL= urn:schemas:httpmail:subject LIKE '%STRINGA DA CERCARE NEL SUBJECT%'"
    Set filtered_items = Folderinbox.Items.Restrict(strFilter)
 
    If filtered_items.Count = 0 Then
        GoTo empty_objects
    End If
 
    For Each olMail In filtered_items
 
        Debug.Print olMail.Subject
        Debug.Print olMail.SenderEmailAddress
        Debug.Print olMail.entryId
        Debug.Print olMail.To
 
    Next olMail
 
empty_objects:
    Set Folderinbox = Nothing
    Set oINS = Nothing
End Sub
 
 


La domanda però sorge spontanea se EntryID di uno stesso messaggio cambia a che serve la possibilità di salvarlo in una tabella se poi quello nella tabella non esiste più in outlook? mi è sfuggito qualcosa?
 
 
 

Il giorno venerdì 4 novembre 2022 alle 07:40:33 UTC+1 BFS ha scritto:

ti confermo quanto da me sospettato ovvero che EntryID può cambiare e quindi non si capisce l'utilità di salvarlo in una tabella se poi non serve per ritrovare quel messaggio in outlook
 
questa è la risposta ufficiale del programmatore che ha pubblicato la sub che mi hai consigliato, puoi leggerla anche in fondo al tuo link
 
link 
https://www.devhut.net/vba-retrieve-an-outlook-message-item/
 
 
--- mia domanda 
   L’ho provata e mi restituisce “Outlook item not found.”
   Il messaggio che cerco però è presente nella cartella outlook posta inviata
   come parametro EntryID gli passo la stringa che identifica il messaggio che ho salvato in una tabella in fase di creazione del messaggio eseguendo .save
 
   Quale potrebbe essere il motivo per cui non trova il messaggio? forse il codice EntryID assegnato in fase di creazione cambia quando il messaggio viene spostato in posta inviata? 
   se cosi fosse come potrei risalire al nuovo EntryID?
--- mia domanda 
 
--- risposta
   The EntryId can change if, for instance if the item is moved. It’s a real pain and something I’ve never understood the reason for. So sometimes it may be better to locate an item by 
   date/time, subject, sender, recipient(s), …
--- risposta
 
--- risposta tradotta
   L'EntryId può cambiare se, ad esempio, se l'elemento viene spostato. È un vero dolore e qualcosa di cui non ho mai capito il motivo. Quindi a volte potrebbe essere meglio individuare 
   un articolo per data/ora, oggetto, mittente, destinatario/i,...
--- risposta tradotta


Ma lo spostamento messaggio da una all'altra cartella, non potresti 
farlo da codice?
Magari ti viene restituito il nuovo EntryID messaggio
 


mi sfugge una cosa
 
il tuo post è "salvare mail outlook sul disco fisso in una cartella"
 
quindi una volta che hai l'id della mail e la salvi su cartella windows 
che ti frega se poi l'id cambia perchè qualcuno sposta la mail in outlook?
 
 
Nella tabella ti memorizzi il percorso del file eml sul disco e non l'id 
e te la recuperi con quello.
Ti metterebbe al riparo da cancellazioni involontarie dell'utente in 
outlook e in più se salvata in share di rete di recuperarla da ogni 
postazione
 
BFS
 
 
 
 
 
 


Credo scriva di 'cartelle' dentro Outlook
Non del sistema operativo
 


l'operatore clicca un pulsante in access che crea una mail outlook in anteprima che salvo con .save e ottengo EntryID
poi però l'operatore modifica a suo piacere la mail e infine clicca il pulsante invia di outlook che mette la mail in cartella "posta inviata" di outlook
nel mentre che la mail passa da bozze (credo) a "inviata" cambia EntryID e quindi quello salvato prima non serve a nulla.
 
Soltanto dopo che l'operatore ha inviato la mail devo salvarla in una cartella su disco c:\miacartella
 
al momento ho risolto mettendo un numero ordine univoco nell'oggetto e utilizzando i metodi restrict di vba per outlook come indicato in qualche post precedente di questa discussione.
 
 
 
 
 
 


non vorrei dire una fesseria ma
se dopo il tuo
.display
metti
.saveAs "c:\miacartella"
 
il codice va interruzione tra display e saveAs
 
quindi nel momento in cui l'operatore clicca su invia si passa a .saveAs
quindi nella tua cartella hai gia l'ultima versione della mail.
a questo punto l'id non ti serve a nulla
memorizzati il percorso di dove hai salvato il file e stop
 
BFS
 


interessante lo proverò.