VBA E-Mail pdf-Anhang drucken

VBA - Visual Basic for Application

Outlook hält bereits viele Funktionen bereit, mit welchen sich bestimmte Aufgaben automatisieren bzw. vereinfachen lassen. Dazu zählen unter anderem die Outlook-Regeln.
Jedoch gibt es aber nicht für alle Aufgaben eine passende Funktion. Dafür kann man aber in Mircosofts Outlook VBA (Visual Basic for Applications) benutzen, um flexibel eigene Funktionen zu programmieren und Arbeitsabläufe anzupassen. Dies können die wenigsten anderen E-Mail-Programme vorweisen.

Will man einen PDF-Anhang aus einer E-Mail heraus drucken, dann öffnet man meistens die PDF-Datei im Adobe Reader und hangelt sich dort zum Drucken-Menü vor. Das sind bei wiederkehrenden Aufgaben unnötig viele Klicks. Und meistens sind noch andere Arbeitsabläufe damit verbunden, wie das Speichern des E-Mail Anhang unter einem bestimmten Pfad.

Ein typischer routinemäßiger Arbeitsprozess kann hier sein, dass man per Mail eine Rechnung erhält. Diese möchte man für die Buchhaltung unter einem bestimmten Pfad speichern und dann gleichzeitig auf den Drucker schicken.

Bestseller Nr. 1

PDF-Datei aus E-Mail automatisch Drucken

Das Drucken einer PDF-Datei, die als Anhang einer E-Mail beigefügt ist, kann man über den folgenden VBA-Code vornehmen. Mittels diesem VBA-Code werden alle PDF-Anhänge der ausgewählten E-Mails auf den Standard-Drucker gesendet.

Zum VBA-Editor gelangt man über die Tastenkombination Strg+F11 oder über die Registerkarte Entwicklertools ⇒ Visual Basic. (Die Registerkarte Entwicklertools erscheint nicht standardmäßig im Outlook. Hier kann man das anpassen: Datei zu Optionen Menüband anpassen Hauptregisterkarten.)


Public Sub PrintSelectedAttachments()
  Dim Exp As Outlook.Explorer
  Dim Sel As Outlook.Selection
  Dim obj As Object
  Set Exp = Application.ActiveExplorer
  Set Sel = Exp.Selection
  For Each obj In Sel
    If TypeOf obj Is Outlook.MailItem Then
      PrintAttachments obj
    End If
  Next
End Sub

Private Sub PrintAttachments(oMail As Outlook.MailItem)
  On Error Resume Next
  Dim colAtts As Outlook.Attachments
  Dim oAtt As Outlook.Attachment
  Dim sFile As String
  Dim sFileType As String
  Dim ATTACHMENT_DIRECTORY As String

'Pfad, wo Anlage temporär zwischen gespeichert wird
ATTACHMENT_DIRECTORY = "c:\Users\MeinBenutzer\Downloads\"

  Set colAtts = oMail.Attachments

  If colAtts.Count Then
    For Each oAtt In colAtts

      sFileType = LCase$(Right$(oAtt.FileName, 4))

      Select Case sFileType
      Case ".pdf"
        sFile = ATTACHMENT_DIRECTORY & oAtt.FileName
        oAtt.SaveAsFile sFile
        ShellExecute 0, "print", sFile, vbNullString, vbNullString, 0
        'warten eine bestimmte Zeit (Millisekunden) bis Drucken abgeschlossen
        Sleep 10000
        'wenn erfolgreich gedruck, dann Datei wieder löschen
        Kill sFile
      End Select
    Next
  End If
End Sub

Wie man sieht, wird hier der Befehl ShellExecute ausgeführt. Dieser Befehl greif auf eine WinAPI zu. Dies ist notwendig, weil es sich beim Drucken um einen Dienst außerhalb der Microsoft Outlook-Umgebung handelt. Damit das Drucken der PDF-Datei funktioniert, muss man noch am Anfang des VBA-Moduls, vor dem eigenlichen Code, die folgende DLL einbinden.


Private Declare Function ShellExecute Lib "shell32.dll" Alias _
  "ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation As String, _
  ByVal lpFile As String, ByVal lpParameters As String, _
  ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
Private Declare PtrSafe Sub Sleep Lib "kernel32.dll" (ByVal dwMilliseconds As Long)

Die zweite Deklaration dient dazu die Sleep-Funktion zu deklarieren. Im Programm-Code verwenden wird dann Sleep, um eine bestimmte Zeit abzuwarten, bis die ShellExecute-Funktion das Drucken abgeschlossen hat. Die Wartezeit muss in Millisekunden angegeben werden und sollte ggf. angepasst werden, wenn der Druckvorgang länger dauert, das es sonst zu einer Fehlermeldung kommt. Danach wird der temporär gespeicherte Anhang wieder gelöscht.

VBA Makro Datei-Anhang Drucken ausführen

Nun hat man ein fertiges Makro, welches sich auch mit weiteren Makros kombinieren lässt. Um auf das Makro zuzugreifen, geht man auf Entwicklertools ⇒ Makro ⇒ Makros-Dialog. Damit das Makro hier erscheint, darf es nicht als Private deklariert sein.

Noch schöner ist, wenn man direkt über den Schnellzugriff darauf zugreifen kann. Die nachfolgenden beiden Screenshots zeigen, wie man dies bewerkstelligen kann.

Screenshot Outlook Schnellzugriff Button zum Ausführen des Makros zuweisen
Outlook Schnellzugriff Button zum Ausführen des Makros zuweisen
Screenshot Outlook Symbolleiste für Schnellzugriff
Befehlsart Makros auswählen und entsprechendes Makro der Symbolleiste für den Schnellzugriff zuweisen

Über den Ändern-Button kann man dann seinem Makro noch ein eigens Icon und einen eigenen passenden Text zuweisen.

AngebotBestseller Nr. 1
Microsoft Office 2021 Home und Business |...
  • Nutzung auf einem PC oder Mac
  • Desktop-Versionen von Word, Excel und PowerPoint
  • Für Privatanwender konzipierte Gratisversion von Microsoft Teams2

21 Kommentare

  1. Hallo,

    vielen Dank für den Code.
    Der Anhang wird auf dem Windows-Standarddrucker gedruckt. Kann man in dem Code noch einen Druckerwechsel einbetten?

    Vielen Dank im Voraus.

    MfG

    1. Hallo,
      ja man kann auch im VBA-Code einen anderen Drucker festlegen. Dazu am besten den folgenden String definieren und diesem den Druckernamen zuweisen:

      Dim printer As String
      printer = Chr(34) & "Microsoft Print to PDF" & Chr(34)

      Chr(34) sind Anführungszeichen, die wichtig für die Shell-Anweisung sind, insbesondere wenn Leerzeichen im String vorkommen. Alternativ könnte man auch “””Microsoft Print to PDF””” schreiben.

      Und dann noch die folgende Codezeile ändern bzw. anpassen, indem “print” zu “printto” geändert wird und als 4.Parameter der Drucker (Variable: printer) eingesetzt wird:

      ShellExecute 0, "printto", sFile, printer, vbNullString, 0

      Will man jedoch, dass der Anwender den Druck auswählen kann, müsste man sich über ein VBA-Formular einen kleinen Drucker-Dialog bauen.

      1. Guten Morgen,
        danke für die schnelle Antwort. Meine VBA-Kenntnisse stützen sich auf bisschen Schul-EDV.
        Bei mir sieht der Code wie folgt aus und es klappt nicht mit dem Druckerwechsel.

        Vielen Dank schonmal für die Hilfe.

        Private Declare Function ShellExecute Lib “shell32.dll” Alias _
        “ShellExecuteA” (ByVal hwnd As Long, ByVal lpOperation As String, _
        ByVal lpFile As String, ByVal lpParameters As String, _
        ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long

        Public Sub PrintSelectedAttachments()
        Dim Exp As Outlook.Explorer
        Dim Sel As Outlook.Selection
        Dim obj As Object
        Set Exp = Application.ActiveExplorer
        Set Sel = Exp.Selection
        For Each obj In Sel
        If TypeOf obj Is Outlook.MailItem Then
        PrintAttachments obj
        End If
        Next
        End Sub

        Private Sub PrintAttachments(oMail As Outlook.MailItem)
        On Error Resume Next
        Dim colAtts As Outlook.Attachments
        Dim oAtt As Outlook.Attachment
        Dim sFile As String
        Dim sFileType As String
        Dim printer As String
        printer = Chr(34) & “\\HSVM09\2. OG Flur auf Ne26:” & Chr(34)
        Set colAtts = oMail.Attachments

        If colAtts.Count Then
        For Each oAtt In colAtts

        sFileType = LCase$(Right$(oAtt.FileName, 4))

        Select Case sFileType
        Case “.pdf”
        sFile = ATTACHMENT_DIRECTORY & oAtt.FileName
        oAtt.SaveAsFile sFile
        ShellExecute 0, “printto”, sFile, printer, vbNullString, 0
        End Select
        Next
        End If
        End Sub

        1. Hm? Da kann ich von der Ferne glaube nicht viel weiterhelfen. Der VBA-Code sieht erstmal gut und passend aus. Man müsste es in diesem Fall mal debuggen. Kommen irgendwelche Fehlermeldungen? Meine Vermutung wäre, dass es an dem Druckernamen im Zusammenspiel mit dem ShellExecute liegt. Ist das der Druckername wie er in den Druckerdialogen/-einstellungen erscheint. Sieht ein bisschen nach Netzwerkpfad aus. Vielleicht macht der doppelte Backslash oder der Punkt im Druckname Probleme!?

          1. Es kommen keinerlei Fehlermeldungen. Er druckt einfach auf dem Standarddrucker.

            Das ist der Druckername laut VBA-Auslesung, aber ja , es ist ein Netzwerkdrucker.

  2. Hallo,
    bei dem Code speichert er die Dateien automatisch unter “Dokumente”.
    Ist es möglich noch einen speziellen Speicherort mitzugeben?

    Vielen Dank im Voraus.

    1. Hallo Timo,
      du hattest recht. Die Dateien wurden automatisch unter “Dokumente” gespeichert. Das lag daran, dass der Variable ATTACHMENT_DIRECTORY kein Speicherpfad zugewiesen war. Zum Drucken muss die Datei aber temporär zwischengespeichert werden.
      Ich habe jetzt den Code im Artikel so angepasst, dass man den Pfad angeben kann, wo die Datei zwischengespeichert wird. Zusätzlich habe ich eine Wartezeit hinzugefügt, bis der Druckvorgang abgeschlossen (Sleep) ist und dann wird die Datei wieder gelöscht (Kill sFile).
      Die Wartezeit muss man ggf. noch individuell anpassen, je nachdem wie lange der Druckvorgang ungefähr benötigt.

      1. Hallo Daniel,

        ich habe jetzt den geänderten Code benutzt. Das speichern klappt ohne Probleme, egal welchen Pfad ich mitgebe.

        Nur der Kill-Befehl funktioniert nicht. Egal auf wie viele Millisekunden ich angebe.

          1. Hallo Timo,
            freut mich, dass es jetzt funktioniert.
            Und es ist interessant zugleich, weil es bei mir ohne Klammern funktioniert. Kenne es bisher so, dass die Argumente nur in Klammern zu setzen sind, wenn man ein Rückgabewert von der Funktion erwartet und einem Objekt/Variablen zuweist.

  3. Hallo,

    dieses Makro ist genau das, wonach ich gesucht habe. Ich bekomme einmal im Monat 70 E-Mails mit Anhang, die ich ausgedruckt brauche, jedoch nur den Anhang und nicht die E-Mail. Habe alles so umgesetzt wie beschrieben, jedoch scheitere ich daran, den Code auf 64 Bit umzuschreiben, kennt sich da jemand besser aus und hat eine Idee, wie dieses Makro in der 64 Bit Outlook 2016 Version auszusehen hat?

    LG

    Eric

    1. Die Frage wäre, was ist das Problem mit der “64bit”-Version oder mit Outlook 2016? Gibt es irgendwelche Fehlermeldungen? Oder eine bestimmte Stelle im Code, wo sich das Makro aufhängt/abbricht?

      1. Ja, beim Debuggen stieß das Programm eine Fehlermeldung aus, dass der Code nicht für 64bit – Versionen geeignet ist, die Lösung ist dann doch einfacher als gedacht.

        einfach den Code um das PtrSafe vor der Function erweitern, schon klappt es.

        Private Declare PtrSafe Function ShellExecute Lib “shell32.dll” Alias _
        “ShellExecuteA” (ByVal hwnd As Long, ByVal lpOperation As String, _

        Nun taucht ein anderes Problem auf, das Makro funktioniert zwar, leider bei mir weder der Speicherort, noch der Kill-Befehl. Er speichert alle PDF auf dem Desktop und löscht diese leider nach getaner Arbeit nicht selbst wieder. Jemand da eine Lösung für mich parat?

        Private Sub PrintAttachments(oMail As Outlook.MailItem)
        On Error Resume Next
        Dim colAtts As Outlook.Attachments
        Dim oAtt As Outlook.Attachment
        Dim sFile As String
        Dim sFileType As String
        Dim ATTACHMENT_DIRECTORY As String

        ‘Pfad, wo Anlage temporär zwischen gespeichert wird
        ATTACHMENT_DIRECTORY = “c:\Users\Backoffice-2\Desktop\test”

        Set colAtts = oMail.Attachments

        If colAtts.Count Then
        For Each oAtt In colAtts

        sFileType = LCase$(Right$(oAtt.FileName, 4))

        Select Case sFileType
        Case “.pdf”
        sFile = ATTACHMENT_DIRECTORY & oAtt.FileName
        oAtt.SaveAsFile sFile
        ShellExecute 0, “print”, sFile, vbNullString, vbNullString, 0
        ‘warten eine bestimmte Zeit (Millisekunden) bis Drucken abgeschlossen
        Sleep 10000
        ‘wenn erfolgreich gedruck, dann Datei wieder löschen
        Kill (sFile)
        End Select
        Next
        End If
        End Sub

        1. Nur eine erste Vermutung: Setzte mal noch ein Backslash hinter dem Dateipfad fürs Zwischenspeichern; also in dieser Form:
          ATTACHMENT_DIRECTORY = “c:\Users\Backoffice-2\Desktop\test\

          1. Danke dir, damit funktioniert das Zwischenspeichern so wie es soll, der Kill-Befehl geht leider noch nicht, aber damit könnte ich leben, muss man halt immer mal den Ordner leeren.

            Gruß

            Eric

  4. Hallo,

    erstmal vielen Dank für die Erstellung und Veröffentlichung dieses Makros. Ich würde gerne noch die Funktion hinzufügen, dass der Druckauftrag nur bei einer (oder mehreren) bestimmten Email ausgeführt wird. Könnte man dies ohne großen Aufwand hinzufügen?

    Vielen Dank im Voraus!

    LG

    Marko

  5. Moin Daniel,
    nochmals Dank für das Makro.
    Folgende Herausforderung habe ich:
    1. Ich möchte, dass die Anhänge im hinterlegten Ordner nicht gelöscht (Kill) werden, sondern erhalten bleiben, sozusagen als digitale Kopie. Ich habe den Code bei “Kill sFile” auskommentiert ( ‘Kill sFile).
    Die Mails aber trotzdem gelöscht, warum?
    2. Wenn ich eine Mail mit 2 Anhängen bekomme und eins ist kein PDF-Anhang, soll dieser Anhang ungleich PDF nicht gedruckt werden. Jedoch druckt das Makro z.B. auch ein Excel aus … Ich bin davon ausgegangen, dass über die Case-Abfrage selektiert wird, dass nur PDF gedruckt werden…

    Hast Du eine Idee?
    Beste Grüße
    Axel

    1. Hier noch der hinterlegte Code:

      Private Declare PtrSafe Function ShellExecute Lib “shell32.dll” Alias _
      “ShellExecuteA” (ByVal hwnd As Long, ByVal lpOperation As String, _
      ByVal lpFile As String, ByVal lpParameters As String, _
      ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
      Private Declare PtrSafe Sub Sleep Lib “kernel32.dll” (ByVal dwMilliseconds As Long)

      Public Sub PrintSelectedAttachments()
      Dim Exp As Outlook.Explorer
      Dim Sel As Outlook.Selection
      Dim obj As Object
      Set Exp = Application.ActiveExplorer
      Set Sel = Exp.Selection
      For Each obj In Sel
      If TypeOf obj Is Outlook.MailItem Then
      PrintAttachments obj
      End If
      Next
      End Sub

      Private Sub PrintAttachments(oMail As Outlook.MailItem)
      On Error Resume Next
      Dim colAtts As Outlook.Attachments
      Dim oAtt As Outlook.Attachment
      Dim sFile As String
      Dim sFileType As String
      Dim ATTACHMENT_DIRECTORY As String

      ‘Pfad, wo Anlage temporär zwischen gespeichert wird
      ATTACHMENT_DIRECTORY = “\\Server\Struktur\Anhaenge\”

      Set colAtts = oMail.Attachments

      If colAtts.Count Then
      For Each oAtt In colAtts

      sFileType = LCase$(Right$(oAtt.FileName, 4))

      Select Case sFileType
      Case “.pdf”
      sFile = ATTACHMENT_DIRECTORY & oAtt.FileName
      oAtt.SaveAsFile sFile
      ShellExecute 0, “print”, sFile, vbNullString, vbNullString, 0
      ‘warten eine bestimmte Zeit (Millisekunden) bis Drucken abgeschlossen
      Sleep 10000
      ‘wenn erfolgreich gedruck, dann Datei wieder löschen
      ‘Kill sFile
      End Select
      Next
      End If
      End Sub

      1. Hi,
        zu 1) verstehe ich leider nicht ganz. Wird die Datei oder Mail gelöscht?
        zu 2) hier könnte ich mir vorstellen, dass die Extraktion der Dateiendung nicht richtig funktioniert. Diese ist nicht besonders schlau umgesetzt. Es werden immer die letzten 4 Zeichen vom Dateipfad genommen. Wenn die Dateiendung aber “.xlsx” ist, dann funktioniert ein case auf “.xlsx” nicht, da nur “xlsx” als Dateiendung extrahiert wurde. Das wäre zumindest meine Vermutung, woran es liegen kann.

  6. Moin Daniel,
    zu 1) Ja, die Datei wird gelöscht, obwohl ich “kill” auskommentiert habe.
    zu 2) ok, schaue ich mir noch einmal an
    VG Axel

Schreibe einen Kommentar zu Eric Antworten abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert