access stampa unione e invio mail personalizzate in pdf

Anonimo
2017-01-13T11:39:27+00:00

Buongiorno a tutti.

E' un po' di tempo che cerco di risolvere questo problema; ho letto, studiato e cercato di applicare al mio caso specifico decine di soluzioni in merito, ma, mancandomi quasi completamente le basi, non riesco nell'intento. Entriamo nel merito:

Lavoro periodico: capita spesso in studio di dover inviare delle lettere circolari personalizzate ai clienti; ho quindi creato un file di word generico "Stampa unione" con campi unione prelevati da una tabella di Access;

Obiettivo: inviare un file PDF personalizzato per ogni cliente come allegato ad una mail e salvare i files Pdf creati in apposita directory (va bene anche un unico file);

Procedura: da una maschera di Access apro il file di word "stampa unione" (pulsante con collegamento ipertestuale ?), lo salvo in una cartella predefinita con un nome specifico (esempio: "Nuove scadenze 2017"); completo il testo del file di word; torno in Access e con un pulsante invio le mail ai singoli destinatari con gli allegati PDF.

Tra le altre cose ho provato ad adattare quanto proposto da Maurizio Capannoli nella sua "Stampa unione e VBA: creare PDF e inviarli via email " ma restituisce una serie di errori che non riesco a superare.

Confido nel vostro prezioso aiuto e ringrazio fin da ora.

Buon week end a tutti.

Andrea Lucca

Microsoft 365 e Office | Access | Per la casa | Windows

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
Risposta accettata dall'autore della domanda
Anonimo
2017-03-02T20:10:16+00:00

ciao Andrea,

se non ci mostri la modifica alla routine come facciamo...? :-)

prova come segue :

      CreateEmailWithOutlook Rs.Fields("Mail"), strsubject, strMessaggio, strFile, CStr(Rs.Fields("ID_clienti"))

passa alla routine che crea l'email l'idcliente.

e modifica come segue la routine CreateEmailWithOutlook  ( in grassetto le modifiche) :

Option Compare Database

    Option Explicit

    Private outLookIstance As Object 'Outlook.Application

    Private Const strPathDichiarazione  As String = "E:\tuoPathSecondoFilePdfDaAllegare" '<<<< personalizzare

Public Function CreateEmailWithOutlook( _

    ByVal MessageTo As String, _

    ByVal Subject As String, _

    ByVal MessageBody As String, _

    ByVal strFile As String, _

    ByVal strID As String)

    ' Define app variable and get Outlook using the "New" keyword

    Dim olMailItem As Object ' Outlook.MailItem  ' An Outlook Mail item

Dim strSecondAtt As String

    ' Create a new email object

        newOlIstance

        Set olMailItem = outLookIstance.CreateItem(0)

    ' Add the To/Subject/Body to the message and display the message

        With olMailItem

            .To = MessageTo

            .Subject = Subject

            .Body = MessageBody

            .Display    ' To show the email message to the user

            .attachments.Add strFile

             strSecondAtt = strPathDichiarazione & "2016" & strID & ".pdf"

If fileExists(strSecondAtt) Then

.attachments.Add strSecondAtt

End If

        End With

        emailFocus2 Subject

    ' Release all object variables

    Set olMailItem = Nothing

End Function

e aggiungi questa funzione che controlla se il file esiste.

Private Function fileExists(ByVal strFile As String) As Boolean

On Error Resume Next

fileExists = (GetAttr(strFile) And vbDirectory) = 0

End Function

se esiste lo alleghi altrimenti no.

la modalità di creazione del strSecondAtt è brutta perché ho preso come riferimento la costante 2016 per l'anno 2016...le costanti sono il male come dicono i veri developers (io faccio mia questa loro indicazione) se devi allegare file dell'anno corrente meglio qualcosa del tipo :

strSecondAtt = strPathDichiarazione & format$(vba.date,"yyyy") & strID & ".pdf"

se invece la scelta dell'anno dovesse dipendere da altro si può ragionare diversamente....

Facci sapere.

ciao, Sandro.

La risposta è stata utile?

0 commenti Nessun commento
Risposta accettata dall'autore della domanda
Anonimo
2017-01-14T13:51:38+00:00

ciao Andrea,

[...]

Ti ringrazio per il complimento circa la pazienza e la buona volontà ! E' vero, quelle non mi mancano, purtroppo mi manca la conoscenza delle basi, in particolare ho una spiccatissima ed innata avversione per i cicli !!!!!

[...]

:-)

[...]

  • non tiene conto della condizione "clienti.invio = true";

[...]

secondo me si invece.

[...]

  • non cicla il recordset ma si limita a creare il Pdf solo per il cliente selezionato !!!;

[...]

per come lo hai impostato devi ciclare il recordsetclone della form visto i parametri passati, ma forse ti è più facile utilizzare il recordset creato ad hoc, passando il campo del recorset, nel codice qui sotto capirai perché

[...]

  • a livello di invio mail non trova l'allegato; temo poi che se anche lo trovasse, così come strutturato, il codice non sarebbe in grado di allegare a ciascun cliente il proprio messaggio personalizzato.

In buona sostanza UNA SCHIFEZZA, anche se spero che tu apprezzi almeno un po' lo sforzo profuso !

[...]

no secondo me no, la logica è giusta e ti sei fermato ad un passo dalla meta.

non trovi l'allegato perché non passi il path correttamente.

[...]

  • ogni volta che faccio un invio accodo in una tabella i campi data, ID cliente, oggetto e path dell'invio fatto;
  • creo una maschera basata su quella tabella che mi permetta di cercare con l'ID cliente oppure con la data oppure con l'oggetto gli invii effettuati.

Ho capito bene ?

[...]

si è esattamente quello che intendo che ti lascio sviluppare in autonomia,

Ovvia che se hai qualche difficoltà siamo qua.

Ti lascio la routine modificata che salva il doc in pdf e crea l'email.

Mi sono limitato a nominare "scolasticamente" il nome del file in pdf con il nome del cliente.

Non vedrei male nominare il file con data in formato americano concatenando nome cliente o suo id, tanto poi con la form basata sulla tabella di cui alla parte che devi sviluppare se serve il file lo individui facilmente.

Ricordati nell'automazione di word di chiudere l'istanza aperta e di distruggere le variabili oggetto, non sempre access fa il suo dovere ( con l'istanza la distruzione deve essere esplicita) nel resettare tutto a fine routine quindi diamogli una mano :-)

L'idea di utilizzare una funzione esterna per la gestione dei bookmarks è buona, non l'ho seguita perché a mio avviso il codice appare ordinato e lineare anche popolando i bookmarks nella routine esistente.

Personalizza il nome dei controlli....comando15...! ed inserisci una gestione errori.

prova la routine che segue :

Private Sub Comando15_Click()

    Dim Rs As DAO.Recordset

    Set Rs = CurrentDb.OpenRecordset("SELECT * FROM clienti WHERE clienti.invio = True ", dbOpenDynaset)

    Dim Wrd As Object, Doc As Object

    Dim Modello As String, NomeFile As String, i As Integer

    Dim Record As String, sql As String

    Dim PercorsoFile As String

    Dim PercorsoPdf As String

    Dim strMessaggio As String

    Dim strsubject As String

     PercorsoFile = "\DS1515PLUS\DatiAziendali\stampa unione"

     PercorsoPdf = "\DS1515PLUS\DatiAziendali\stampa unione\stampe pdf"

     NomeFile = "stampa unione modello demo.dotx"

     NomeDocWord = PercorsoFile & NomeFile

     'NomePDF = PercorsoPdf & Trim(Me.Nome) & "prova.pdf"

     strsubject = "Comunicazione"

     'strFile = PercorsoPdf

     On Error Resume Next

     Set Wrd = GetObject(, "Word.Application")

        If Err.Number = 429 Then

            Set Wrd = CreateObject("Word.Application")

        End If

     On Error GoTo 0

     On Error GoTo errHandler

     Wrd.Visible = False

     'Wrd.Activate

     'ReplSel = Wrd.Options.ReplaceSelection

     'Wrd.Options.ReplaceSelection = True

     Do Until Rs.EOF

            Set Doc = Wrd.Documents.Add(NomeDocWord)

            'Doc.Activate

            strMessaggio = "Gentile " & Rs.Fields("Nome") & vbNewLine

            With Doc.bookmarks

                .Item("nome").Range.Text = Rs.Fields("Nome")

                .Item("indirizzo").Range.Text = Rs.Fields("Indirizzo")

                .Item("frazione").Range.Text = Rs.Fields("Frazione")

                .Item("cap").Range.Text = Rs.Fields("Cap")

                .Item("città").Range.Text = Rs.Fields("Città")

                .Item("mail").Range.Text = Rs.Fields("Mail")

             End With

             strFile = PercorsoPdf & Rs.Fields("nome")

             With Doc

                .saveas FileName:=strFile, _

                        FileFormat:=17   ' wdFormatPDF

                .Close SaveChanges:=False

            End With

            strMessaggio = strMessaggio & "In allegato trasmettiamo la comunicazione in oggetto." & vbNewLine & "Distinti saluti" & vbNewLine & "Studio Pinco pallino."

            CreateEmailWithOutlook Rs.Fields("Mail"), strsubject, strMessaggio, strFile & ".pdf"

            Rs.MoveNext

       Loop

     'Call StampaBookmark(Doc, Wrd, "nome", Me.Nome)

     'Call StampaBookmark(Doc, Wrd, "indirizzo", Me.Indirizzo)

     'Call StampaBookmark(Doc, Wrd, "frazione", Me.Frazione)

     'Call StampaBookmark(Doc, Wrd, "cap", Me.Cap)

     'Call StampaBookmark(Doc, Wrd, "città", Me.Città)

     'Call StampaBookmark(Doc, Wrd, "mail", Me.Mail)

ExiterrorHandler:

    Rs.Close

    Set Rs = Nothing

    Set Doc = Nothing

    Wrd.Quit

    Set Wrd = Nothing

    Exit Sub

errHandler:

  With Err

        MsgBox "ERR#" & .Number _

             & vbNewLine & .Description _

             , vbOKOnly Or vbCritical

  End With

  Resume ExiterrorHandler

End Sub

Ciao, Sandro.

La risposta è stata utile?

0 commenti Nessun commento

70 risposte aggiuntive

Ordina per: Più recente
  1. Anonimo
    2017-03-14T18:39:48+00:00

    ciao Andrea,

    [...]

    ma, soprattutto spero di aver fatto mie le molte cose che ho appreso, in modo da poterle utilizzare in futuro

    [...]

    questo è un aspetto molto importante è più che

    [...]

    ............senza dovervi rompere nuovamente.

    [...]

    credo che lo scambio lungo e proficuo oltre che a risolvere il tuo quesito sarà un spunto importante per coloro che dovessero incontrare le stesse difficoltà.

    Per il resto posta ogni volta che vuoi sei sempre il benvenuto :-)

    [...]

    Buona serata.

    Andrea Lucca

    PS

    Mi vergogno un po' a sfruttare la vostra disponibilità senza poter un minimo contraccambiare9

    buona serata anche e a te e vai sciolto, non ti preoccupare, siam qui apposta :-).

    Ciao, Sandro.

    La risposta è stata utile?

    0 commenti Nessun commento
  2. Anonimo
    2017-03-14T17:32:04+00:00

    Sandro grazie ancora una volta...... F U N Z I O N A alla meraviglia.................. WOW che fenomeno che sei e ti sei anche autodefinito ".....nulla più che un utente come te.....": certo, nella forma non fa una grinza, nella sostanza c'è utente e utente.......

    Con questo lungo colloquio ho raggiunto grazie a tutti voi l'obiettivo prefissato ma, soprattutto spero di aver fatto mie le molte cose che ho appreso, in modo da poterle utilizzare in futuro............senza dovervi rompere nuovamente.

    Buona serata.

    Andrea Lucca

    PS

    Mi vergogno un po' a sfruttare la vostra disponibilità senza poter un minimo contraccambiare9

    La risposta è stata utile?

    0 commenti Nessun commento
  3. Anonimo
    2017-03-14T13:23:49+00:00

    ciao Andrea,

    la buona volontà va sempre premiata.

    Prova come segue :

    EmailCumulative Nz(Rs.Fields("mail")), strsubject, strMessaggio, strFile, strSecondAtt, Rs.Fields("id_clienti")

    Public Function EmailCumulative( _

        ByVal MessageTo As String, _

        ByVal Subject As String, _

        ByVal MessageBody As String, _

        ByVal strFile As String, _

        ByVal strSecondAtt As String, _

        ByVal custId As Long)

    With olMailItem

                    .To = MessageTo

                    .Subject = Subject

                    .Body = MessageBody

                    .Display

                    .Attachments.Add strFile

                    .Attachments.Add strSecondAtt

                    DBEngine(0)(0).Execute "update clienti set emailInviata=-1 where id_clienti=" & custId, &H80

    End With

    Avendo l'id_clienti nel recordset non serve che crei una variabile per passarlo alla sub EmailCumulative.

    Non è sbagliato, ma secondo me è superfluo, inoltre se proprio vuoi utilizzare una variabile visto che l'id_clienti è un long autonumber è bene creare un long e non un integer.

    Lo statement sql è corretto, preferisco mandarla in esecuzione con il metodo execute.

    Nel momento in cui crei uno statement in VBA, ricordati di concatenare la stringa correttamente, in modo che la parte stringa sia stringa e la parte numerica, ovviamente numerica nel tuo caso l'id_clienti.

    Se inserisci tutto tra virgolette il tutto viene interpretato come stringa e ovviamente non può funzionare.

    un saluto, ciao.

    Sandro.

    La risposta è stata utile?

    0 commenti Nessun commento