Die Probleme mit der API:
Große Probleme:
1) Mail Subject Text im Header von Outlook mit Umlauten wird nicht richtig dargestellt; Mit neuen Templates nach dem Upgrade auf 22.2.3 erstellt, oder Template wurde aktualisiert.
Das Text für das Feld „EMail Subject“ Template dazu: Dies ist das Newsletter äöo subject - #MAIL_SUBJECT#.
Der erste Teil des Strings diente nur dazu zu beweisen das Umlaute an sich übertragen werden können, das Problem also in dem Parsen von #MAIL_SUBJECT# liegen muss.
2) Inline Images werden in der Apple Welt leider inline und dann nochmal als Anhang geöffnet angezeigt, in der MS Welt klappt es in Outlook aber perfekt.
Kleine / keine Probleme
3) Wird das ganze über SQL*Developer/SQL*Plus getestet, muss zuvor eine APEX Session gesetzt werden. Nach dem ersten Aufruf eines Templates wird diese in der Session gecached und nicht mehr neu aus der Definition geladen. Das macht ja auch Sinn wenn eine große Anzahl von Mails versandt werden, diese nicht immer neu aus den Metadaten zu lesen. Allerdings muss dann beachtet werden, das bei jeder Änderung man sich auch wieder aus- und einloggt um eine saubere neue Session zu erhalten, sonst wundert man sich warum sich in der Mail gar nichts verändert.
Lösung:
Für alles gibt es eine Lösung…
Zu 1) Sogar relativ einfach, im Subjekt muss mit !RAW (#MAIL_SUBJECT!RAW#) verhindert werden das die Substitution nochmal geparst wird!
Zu 2) Kurzfristig auf inline verzichten und mittelfristig Oracle nerven, das die Mail RFC kleinteilig besser umgesetzt wird.
zu 3) Das muss man einfach nur wissen, dann spart man sich etwas Zeit beim Verstehen warum Änderungen am Template nicht gleich sichtbar werden.
Anbindung E-Mail Relay, am besten verschlüsselt ⇒ Oracle Apex 5.0 Mail Versandt mit SSL -Hinterlegen einer ACL's in 11g und 12c und Hinterlegen von SSL Zertifkaten
Anzahl der Mails pro Tag auf Instance Ebene höher setzen, Default 1000, für produktive Umgebung meist zu klein.
Einstellung auf der APEX Instance:
Prüfen ob der APEX Mail Job alle 5 Minuten auch wirklich regelmäßig zur erwarten Zeit läuft; Problem können zum Beispiel ein zu niedrige JOB_QUEUE Parameter Eintrag sein.
Ab Apex 22.3 scheint sich das Mail Template grundlegende geändert zu haben, alte Mail Templates unterstützen keine „Template Directives“, mit diesen „Template Directives“ kann zusätzliche Logik in das Templating (if then / else /case etc.) in so einer Art PHP Stil eingebettet werden.
Als Template kann ein reines Text Template hinterlegt werden oder auch ein komplexes HTML Template bei hohen Layout Anforderungen. Alternativ solle auch bei einem HTML Template der Texte Template Bereich gefüllt werden, kann der E-Mail Client keine HTML oder wurde das dort verboten, kann der E-Mail Client beim Empfänger auf TEXT zurückgreifen.
Durch das interessante Feature „Template Directives“ hat sich das Parsing Verhalten verändert. Per Default werden Umlaute nun in HTML Notation umgewandelt. Mit dieser kann der E-Mail Client aber nichts anfangen und zeigt keine Umlaute mehr an (siehe Screenshot oben).
Das betrifft nur neue oder nicht migrierte Templates und führt dazu das schnell ein halber Tag verbraucht wird weil die Umlaute nicht dargestellt werden im neuen Code, in der anderen App mit ähnlichen Code aber alles funktioniert.
D.H. im Subjekt muss mit !RAW (#MAIL_SUBJECT!RAW#) verhindert werden das die Substitution nochmal geparst wird-
Ist der Fehler erkannt ist er schnell gelöst, mit dem ! Syntax in Ersetzungsvariablen lässt sich der Text im Original ausgeben und das Problem ist behoben. Wäre schön wenn das in der Online Hilfe gestanden wäre, so Effekte dämpfen doch die APEX Begeisterung kurzfristig wieder sehr stark.
Siehe dazu Controlling Output Escaping in Substitution Strings ⇒ https://docs.oracle.com/en/database/oracle/application-express/20.1/htmdb/understanding-substitution-strings.html#GUID-CA3ABA44-D03D-4396-A527-B160F1FFE933
Das HTML Template besteht aus mehreren Bereichen, auf die sich im Advanced Template dann wieder referenzieren läßt.
Damit lässt sich das Template besser strukturieren.
Mit der APEX Methode pex_mail.send mit dem Parameter p_placeholders können nun die Platzhalter im Template über einen JSON Record mit allen Ersetzungstexten „ausgefüllt“ werden.
Das funktioniert auch wie beschrieben; wie das aufgerufen werden muss wird im Template sogar generiert:
BEGIN apex_mail.send ( p_to => email_address_of_user, p_template_static_id => 'MYTEMPLATE', p_placeholders => '{' || ' "TITEL":' || apex_json.stringify( some_value ) || '}' ); END;
Wie das prinzipell funktioniert ist auf folgenden Seiten auch gut beschrieben:
Im nächsten Schritt war die Idee die Bilder in dem HTML Template in die Mail einzubinden, dann ist kein Nachladen von Bildern erforderlich und Datenschutz Einstellungen etc. sind nicht mehr so technisch wichtig.
Seit APEX 21.2 wird es auch etwas von APEX unterstützt, mit einen Einfachen Metoden Aufruf lassen sich Bilder in die E-Mail integrieren, die ID des Bildes wird zuvor mit eine eigenen Directive src=„cid:xxx“ refenziert.
Wie:
<img src="cid:my_company.jpg" alt="Company Logo" >
Nun muss das Bild mit der ID my_company.jpg in der Mail eingebettet werden und dann kann oder kann auch nicht der E-Mail Client das richtig anzeigen.
Ob das wie gewünscht klappt wird leider im Zusammenspiel der Implementierung des ganzen in APEX und der Implementierung im Mail Klient ermittelt.
Die aktuelle Implementierung in APEX triff anscheinend recht gut die Interpretation des Standards dahinter im MS Outlook Client.
Allerdings scheint dies wiederum nicht für den Standard E-Mail Client auf einen Apple Endgerät (Notebook/Smartphone) zutreffen. Die Inline Images werden zwar in der HTML ohne Fehler angezeigt, aber am Ende der Mail nochmals aufgelistet für den Download und erscheinen damit doppelt in der Mail.
Die Protokolle für E-Mail sind schon relativ lange im Einsatz und wurden schon immer sehr variabel ausgelegt. Wer nun hier an welcher Stelle was tun muss das es am Ende geht, ist wohl auch nicht trivial.
Siehe dazu https://stackoverflow.com/questions/3902455/mail-multipart-alternative-vs-multipart-mixed , dort findet sich ein gutes Diagramm bzgl. der unterschiedlichen Reihenfolgen mit denen eine Multipart Message aufgebaut werden kann.
Allerdings zeigen Tests mit Mail aus Apple Quellen, das es besser gehen kann, diese Mails mit Inline Images werden auf beiden System korrekt angezeigt.
Code zum Anbinden der Bilder, in dem Fall werden alle Bilder in einem Static Files Ordner an das Template gehängt:
.. IS .. cursor c_news_letter_images(p_app_id NUMBER) IS SELECT REPLACE(filename,'newsletter_images/','') AS filename , blob_content , mime_type , REPLACE(filename,'newsletter_images/','') AS content_id FROM apex_application_files WHERE flow_id = p_app_id AND filename LIKE 'newsletter_images/%'; .. BEGIN FOR rec IN c_news_letter_images(p_app_id => p_app_id) loop apex_mail.add_attachment( p_mail_id => v_mail_id , p_attachment => rec.blob_content , p_filename => rec.filename , p_mime_type => rec.mime_type , p_content_id => rec.content_id ); END loop; ... END;
Über den Aufruf von „apex_mail.add_attachment“ können dann Dateien der Mail hinzugefügt werden.
.. IS CURSOR c_get_attachment(p_file_id NUMBER) IS SELECT f.FILENAME , f.MIMETYPE , f.FILE_CONTENT FROM DOK_FILES f WHERE f.ID = p_file_id ; BEGIN .. FOR file_rec IN c_get_attachment( p_file_id => p_file_id ) LOOP apex_mail.add_attachment( p_mail_id => v_mail_id, p_attachment => file_rec.FILE_CONTENT, p_filename => file_rec.FILENAME, p_mime_type => file_rec.MIMETYPE); END LOOP; ... END;
Hier ein Beispiel am Stück, ohne großes Logging und Exception Handling, in der Praxis würde das entsprechend optimiert in eine Package ausgelagert und mit logger erweitert.
DECLARE -- get inline Images from Apex Static Resource cursor c_news_letter_images(p_app_id NUMBER) IS SELECT REPLACE(filename,'newsletter_gpi/','') AS filename , blob_content , mime_type , REPLACE(filename,'newsletter_gpi/','') AS content_id FROM apex_application_files WHERE flow_id = p_app_id AND filename LIKE 'newsletter_gpi/%'; -- get PDF from application document store cursor c_get_attachment(p_file_id NUMBER) IS SELECT f.FILENAME , f.MIMETYPE , f.FILE_CONTENT FROM GPI.DOK_FILES f WHERE f.ID = p_file_id ; v_mail_id NUMBER; v_workspace_id NUMBER; v_placeholders CLOB; BEGIN -- ------------------------------------------- -- Set Apex Workspace ID and Security Group ID SELECT workspace_id INTO v_workspace_id FROM apex_applications WHERE apex_applications.application_id = (SELECT nvl(nv('APP_ID'), 250) FROM dual); apex_util.set_security_group_id(p_security_group_id => v_workspace_id); IF nv('APP_ID') IS NULL THEN apex_session.create_session(p_app_id => 250, p_page_id => 1, p_username => 'SYSTEM', p_call_post_authentication => FALSE); END IF; -- ------------------------------------------- -- Fill the Template Record with values for the template apex_json.initialize_clob_output; apex_json.open_object; apex_json.write('DATUM' , '03.04.2023',TRUE); apex_json.write('ANREDE' , 'Anrede',TRUE); apex_json.write('MAIL_SUBJECT' , 'Ein Mail Subject mit ÄÖÜ und öäü',TRUE); apex_json.write('MAIL_BODY' , 'Ein Mail Text mit ÄÖÜ und öäü',TRUE); apex_json.close_object; v_placeholders:=apex_json.get_clob_output; apex_json.free_output; -- ------------------------------------------- -- prepare the mail v_mail_id:=apex_mail.send ( p_to => 'info@pipperr.de' , p_template_static_id => 'NEWSLETTER' , p_application_id => 250 , p_from => 'info@pipperr.de' , p_placeholders => v_placeholders ); -- ------------------------------------------- -- add inline images -- Rec.content_id value must match cid:content_id in HTML Template -- FOR rec IN c_news_letter_images(p_app_id => 250) loop apex_mail.add_attachment( p_mail_id => v_mail_id , p_attachment => rec.blob_content , p_filename => rec.filename , p_mime_type => rec.mime_type , p_content_id => rec.content_id ); END loop; -- ------------------------------------------ -- add Attachment FOR file_rec IN c_get_attachment( p_file_id => 56) loop apex_mail.add_attachment( p_mail_id => v_mail_id, p_attachment => file_rec.FILE_CONTENT, p_filename => file_rec.FILENAME, p_mime_type => file_rec.MIMETYPE); END loop; -- commit; -- ------------------------------------------ -- sent mail now apex_mail.push_queue; END; /
SELECT * FROM apex_mail_queue;
Oracle:
Web: