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.
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.
Über den Ändern-Button kann man dann seinem Makro noch ein eigens Icon und einen eigenen passenden Text zuweisen.
- Für eine Person
- auf bis zu 5 Geräten gleichzeitig nutzen
- funktioniert auf PC, Mac, iPhone, iPad und Android-Smartphones und -Tablets
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
Hallo,
ja man kann auch im VBA-Code einen anderen Drucker festlegen. Dazu am besten den folgenden String definieren und diesem den Druckernamen zuweisen:
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:
Will man jedoch, dass der Anwender den Druck auswählen kann, müsste man sich über ein VBA-Formular einen kleinen Drucker-Dialog bauen.
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
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!?
Es kommen keinerlei Fehlermeldungen. Er druckt einfach auf dem Standarddrucker.
Das ist der Druckername laut VBA-Auslesung, aber ja , es ist ein Netzwerkdrucker.
Hallo,
bei dem Code speichert er die Dateien automatisch unter „Dokumente“.
Ist es möglich noch einen speziellen Speicherort mitzugeben?
Vielen Dank im Voraus.
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.
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.
Problem gelöst.
Das sFile hinter dem Kill-Befehl muss in Klammern gesetzt werden.
Kill (sFile) , dann funktioniert es einwandfrei.
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.
Ich muss mich nun doch nochmal melden.
Mal funktioniert der Kill-Befehl und dann bei der nächsten Ausführung des Befehls nicht.
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
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?
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
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\”
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
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
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
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
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.
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