CzechIdM – Java – E-maily s přílohou
Minulý týden jsem naučil náš Identity Manager CzechIdM odesílat e-maily s přílohami. Situací, ve kterých se to může hodit, je celá řada: předvyplněný formulář v PDF k tisku, konfigurační soubor k nově zřízené VPN, certifikát nebo třeba aktuální verze telefonního seznamu. V článku vás rychle s novou funkcí seznámím, naučím vás ji používat a společně se podíváme, jak CzechIdM tvoří instanci třídy MimeMessage, která se pro odesílání e-mailu z Javy standardně používá.
Třída Application
Identity Manager CzechIdM ctí obvyklé rozdělení na datovou, aplikační a prezentační vrstvu. Odesílání e-mailu provádí samozřejmě vrstva aplikační – tuto službu poskytuje především procesům, které jsou napsány na míru zákazníkovi. Univerzálním rozhraním aplikační vrstvy pro zákaznické procesy je třída Application. Na ní coby programátoři a administrátoři CzechIdM najdete spoustu užitečných statických metod, logováním do auditního logu počínaje a ověřováním práv přihlášeného uživatele konče.
Odesílání e-mailů mají na starost dvě statické metody: sendEmailToIdentity a sendEmailToAddress. Obě jsou přetížené, tedy existují ve více variantách s různými počty parametrů. My se budeme zabývat pouze těmi nejobecnějšími, ve kterých může programátor uvést parametrů nejvíc. Jsou to:
Application.sendEmailToIdentity(String userName, String emailTemplate, Map params, String language, List<EmailAttachment> attachments) Application.sendEmailToAddress(String address, String emailTemplate, Map params, String language, List<EmailAttachment> attachments)
Volání metod
Parametr userName, respektive address určují adresáta zprávy (buď názvem identity v CzechIdM nebo přímo e-mailovou adresou), emailTemplate označuje šablonu, která má být pro sestavení zprávy použita a params značí atributy zprávy, které mají být do šablony vloženy. Parametrem language lze zvolit jazyk, pokud šablona existuje ve více jazykových mutacích. Zadáte-li null, zvolí se první nalezená šablona. Poslední parametr – attachments – je nový a značí seznam příloh k odeslání.
Instance třídy EmailAttachment představuje jednu přílohu. CzechIdM umí posílat přílohy dvěma způsoby – buď odešle soubor existující někde na disku, nebo dynamicky generované pole bytů. Třída EmailAttachment představuje jen zapouzdřené informace o jedné příloze, jako programátor nebo administrátor bohatě vystačíte s jejími dvěma konstruktory:
EmailAttachment(String path, String fileName) EmailAttachment(byte[] bytes, String mimeType, String fileName)
První značí přílohu uloženou v již existujícím souboru na disku (cesta v parametru path), druhý slouží k odeslání pole bytů (parametr bytes). Pomocí parametru fileName lze přílohu přejmenovat pro oči adresáta. Parametr mimeType umožní blíže specifikovat, jak mají být byty interpretovány – jestli jako obrázek, text, video…
Příklad
Následující kód odesílá přílohu postupně oběma způsoby, jako pole bytů i jako existující soubor na disku:
import eu.bcvsolutions.idm.app.Application;
import eu.bcvsolutions.idm.app.email.EmailAttachment;
HashMap params = new HashMap();
//mapa parametru. Temito parametry bude doplnena e-mailova sablona, #{attr1} v sablone bude nahrazeno retezcem "val1"
params.put("attr1", "val1");
params.put("attr2", "val2");
params.put("attr3", "val3");
//seznam priloh, ktere v mailu odesleme
List attachments = new ArrayList();
//prilohy lze pridat dvema zpusoby - bud primym predanim cesty k souboru a nazvu, pod jakym ma byt predan uzivateli
EmailAttachment attach1 = new EmailAttachment("/opt/attachments/ahoj.txt", "ahoj.txt");
//nebo primym predanim pole bytu vcetne mime typu a nazvu souboru
byte[] bytes = {0x41, 0x48, 0x4F, 0x4A};
EmailAttachment attach2 = new EmailAttachment(bytes, "text/plain", "ahoj.txt");
attachments.add(attach1);
attachments.add(attach2);
Application.sendEmailToAddress("moje.adresa@test.com", "sablonaTestovaci", params, "cz", attachments);
Jak to funguje uvnitř
Nejdůležitější částí kódu je sestavení MimeMessage, tedy instance třídy, která bude následně odeslána. V CzechIdM se o tento úkol stará metoda createMimeMessage na třídě IdMMailerQueueListener. Netradiční je především použití třídy Multipart, která umožňuje sestavit zprávu z více částí, přičemž některými částmi jsou právě přibalované přílohy:
private MimeMessage createMimeMessage(Session session, MapMessage mapMessage) throws AddressException, MessagingException, JMSException {
Charset charset = Charset.forName("UTF-8");
MimeMessage mimeMessage = new MimeMessage(session);
mimeMessage.setFrom(new InternetAddress(mapMessage.getString(Constants.EMAIL_FROM)));
InternetAddress [] recipients = { new InternetAddress(mapMessage.getString(Constants.EMAIL_TO)) };
mimeMessage.setRecipients(javax.mail.Message.RecipientType.TO, recipients);
mimeMessage.setSubject(mapMessage.getString(Constants.EMAIL_SUBJECT), charset.name());
mimeMessage.setSentDate(new java.util.Date());
Multipart multipart = new MimeMultipart();
// cast s textem
MimeBodyPart messageBodyPart = new MimeBodyPart();
//naplnim cast textem
messageBodyPart.setText(mapMessage.getString(Constants.EMAIL_CONTENT), charset.name());
messageBodyPart.setHeader("Content-Type", mapMessage.getString(Constants.EMAIL_CONTENT_TYPE) + "; charset=" + charset.name());
multipart.addBodyPart(messageBodyPart);
//zpracovani priloh, ktere jsou z technickych duvodu predany serializovane
byte[] serializedList = mapMessage.getBytes(Constants.EMAIL_ATTACHMENTS);
ObjectInputStream ois = null;
List<EmailAttachment> attachs = new ArrayList<EmailAttachment>();
if (serializedList != null) {
try {
ois = new ObjectInputStream(new ByteArrayInputStream(serializedList));
attachs = (List<EmailAttachment>) ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//postupne pridam do zpravy vsechny prilohy, ktere mi byly zadany
for (EmailAttachment attach : attachs) {
messageBodyPart = new MimeBodyPart();
DataSource source = null;
//podle typu prilohy se rozhodnu, jak budu nacitat data
switch(attach.getType()) {
case FILE:
File attachment = new File(attach.getFilePath());
if (!attachment.canRead() || attachment.isDirectory() || attachment.isHidden()) {
Application.logError("Attachment " + attachment.getAbsolutePath() + " was not sent!", new Object[0]);
throw new RuntimeException("Attachment failed: " + attach.getFilePath());
}
source = new FileDataSource(attachment);
break;
case BYTES:
source = new ByteArrayDataSource(attach.getBytes(), attach.getMimeType());
break;
default:
throw new RuntimeException("Unknown EmailAttachment Type " + attach.getType());
}
messageBodyPart.setDataHandler(new DataHandler(source));
messageBodyPart.setFileName(attach.getFileName());
multipart.addBodyPart(messageBodyPart);
}
// pridam vsechny casti do zpravy
mimeMessage.setContent(multipart);
mimeMessage.saveChanges();
//zprava je pripravena k odeslani
return mimeMessage;
}
Závěr
V článku jsem vás naučil odesílat prostřednictvím CzechIdM e-maily s přílohou a nechal jsem vás nahlédnout do jedné z klíčových procedur aplikační vrstvy, která používá běžné mechanismy Javy. Kdybyste se chtěli na cokoli zeptat, napište mi na vojtech.matocha@bcvsolutions.eu.



