XSLT převod XHTML na prostý text: mailto odkazy nebudou obsahovat duplicitně adresu
1 package cz.frantovo.postak;
4 import java.io.StringReader;
5 import java.io.StringWriter;
6 import java.util.ArrayList;
7 import java.util.Collection;
8 import java.util.Properties;
9 import java.util.logging.Level;
10 import java.util.logging.Logger;
11 import java.util.regex.Pattern;
12 import javax.mail.Address;
13 import javax.mail.Authenticator;
14 import javax.mail.MessagingException;
15 import javax.mail.PasswordAuthentication;
16 import javax.mail.Session;
17 import javax.mail.Transport;
18 import javax.mail.internet.MimeBodyPart;
19 import javax.mail.internet.MimeMessage;
20 import javax.mail.internet.MimeMultipart;
21 import javax.xml.transform.Transformer;
22 import javax.xml.transform.TransformerFactory;
23 import javax.xml.transform.stream.StreamResult;
24 import javax.xml.transform.stream.StreamSource;
27 * Odešle hromadnou zprávu pomocí SMTP.
33 private static final String KÓDOVÁNÍ = "UTF-8";
34 private static final Logger log = Logger.getLogger(Postak.class.getName());
35 /** Regulární výraz pro správnou e-mailovou adresu */
36 private static String REGULARNI_EMAIL = "^[_a-zA-Z0-9\\.\\-]+@[_a-zA-Z0-9\\.\\-]+\\.[a-zA-Z]{2,4}$";
37 private Nastaveni nastaveni;
38 private TransformerFactory transformerFactory;
40 public Postak(Nastaveni nastaveni) {
41 this.nastaveni = nastaveni;
42 transformerFactory = TransformerFactory.newInstance();
45 public void setNastaveni(Nastaveni nastaveni) {
46 this.nastaveni = nastaveni;
50 * Nízkoúrovňová odesílací metoda, která už nekontroluje limit příjemců.
51 * Pokud se nevejdou do limitu SMTP serveru, vyhazuje výjimku.
53 * TODO: lepší to bude nestaické - nastavení si vyžádat v konstruktoru
55 private void odesliSMTP(HromadnaZprava zprava) throws MessagingException {
57 if (zkontrolujZpravu(zprava) && zkontrolujNastaveni(nastaveni)) {
59 /** Inicializace SMTP */
60 Properties smtpVlastnosti = System.getProperties();
61 smtpVlastnosti.put("mail.smtp.host", nastaveni.getPostovniServer());
62 smtpVlastnosti.put("mail.smtp.port", String.valueOf(nastaveni.getPostovniPort()));
64 if (nastaveni.getPostovniPort() == 465) {
65 if (new File(nastaveni.getCestaKCertifikatum()).exists()) {
66 System.setProperty("javax.net.ssl.trustStore", nastaveni.getCestaKCertifikatum());
67 log.log(Level.INFO, "Používám vlastní důvěryhodné certifikáty: {0}", nastaveni.getCestaKCertifikatum());
69 /** TODO: neřídit se číslem portu, ale přidat příznak pro šifrování */
70 smtpVlastnosti.put("mail.smtp.starttls.enable", "true");
71 smtpVlastnosti.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
72 smtpVlastnosti.put("mail.smtp.socketFactory.port", String.valueOf(nastaveni.getPostovniPort()));
73 smtpVlastnosti.put("mail.smtp.socketFactory.fallback", "false");
75 * NAHRÁNÍ CERTIFIKÁTU:
76 * 1) stáhneme si certifikát (---BEGIN CERTIFICATE---) a uložíme do vse_ca.cer
77 * 2) keytool -importcert -file vse_ca.cer -keystore DuveryhodneCertifikaty.keystore
78 * -storepass "changeit"
79 * Pokud daný soubor existuje, program ho používá, pokud ne, používá certifikáty
80 * uložené v systému (Javovské).
84 PostakuvHeslovnik heslovnik = new PostakuvHeslovnik();
85 if (nastaveni.getPostovniJmeno() != null && nastaveni.getPostovniJmeno().length() > 0) {
86 heslovnik.setJmenoHeslo(nastaveni.getPostovniJmeno(), nastaveni.getPostovniHeslo());
87 smtpVlastnosti.put("mail.smtp.auth", "true");
88 log.log(Level.FINEST, "Používám pro SMTP jméno a heslo");
91 Session smtpRelace = Session.getInstance(smtpVlastnosti, heslovnik);
93 smtpRelace.setDebug(true);
94 smtpRelace.setDebugOut(System.out);
96 /** Sestavení zprávy */
97 MimeMessage mimeZprava = new MimeMessage(smtpRelace);
98 mimeZprava.setFrom(zprava.getOdesilatel());
99 if (zprava.getOdpovedetKomu() != null) {
100 Address[] odpovedetKomu = {zprava.getOdpovedetKomu()};
101 mimeZprava.setReplyTo(odpovedetKomu);
103 naplnPrijemce(mimeZprava, zprava);
104 mimeZprava.setSubject(zprava.getPredmet());
105 mimeZprava.setHeader("User-Agent", "https://frantovo.cz/projekty/SuperPostak/");
106 mimeZprava.setHeader("Precedence", "bulk");
108 switch (zprava.getFormát()) {
110 mimeZprava.setText(zprava.getText(), KÓDOVÁNÍ);
113 mimeZprava.setText(zprava.getText(), KÓDOVÁNÍ, "html");
116 MimeMultipart multipart = new MimeMultipart("alternative");
117 mimeZprava.setContent(multipart);
119 MimeBodyPart textováČást = new MimeBodyPart();
120 MimeBodyPart xhtmlČást = new MimeBodyPart();
122 textováČást.setText(xhtmlNaProstýText(zprava.getText()), KÓDOVÁNÍ);
123 xhtmlČást.setContent(zprava.getText(), "text/html; charset=" + KÓDOVÁNÍ);
125 multipart.addBodyPart(textováČást);
126 multipart.addBodyPart(xhtmlČást);
130 /** Vlastní odeslání */
131 Transport.send(mimeZprava);
134 MessagingException e = new MessagingException("Zpráva nebo nastavení jsou nevyhovující");
135 log.log(Level.SEVERE, null, e);
141 private String xhtmlNaProstýText(String xhtml) throws MessagingException {
143 Transformer textTransformer = transformerFactory.newTransformer(new StreamSource(getClass().getClassLoader().getResourceAsStream("cz/frantovo/postak/odchozíEmailText.xsl")));
145 StringReader input = new StringReader(xhtml);
146 StringWriter output = new StringWriter(xhtml.length());
147 textTransformer.transform(new StreamSource(input), new StreamResult(output));
149 return output.toString();
150 } catch (Exception e) {
151 throw new MessagingException("Chyba při XSL transformaci zprávy na prostý text.", e);
156 * Nastaví zprávě (MimeMessage) všechny příjemce, které najde ve zprávě a nastavení.
157 * Respektuje typy příjemců: komu, kopie, skrytá kopie.
159 private static void naplnPrijemce(MimeMessage mimeZprava, HromadnaZprava zprava) throws MessagingException {
161 * Příjemci se budou definovat pouze ve zprávě.
162 * Z nastavení se brát nebudou (výchozí příjemci už ve zprávě budou).
164 ArrayList<InternetAddressKomu> prijemci = zprava.getPrijemci();
165 for (InternetAddressKomu komu : prijemci) {
166 if (zkontrolujAdresu(komu)) {
167 mimeZprava.addRecipient(komu.getTyp(), komu);
172 /** Vypíše do logu seznam příjemců */
173 public static void vypisPrijemce(Collection<InternetAddressKomu> prijemci) {
174 for (InternetAddressKomu p : prijemci) {
175 log.log(Level.INFO, p.toString());
179 /** Veřejná odesílací metoda.
180 * Postará se o rozdělení zpráv na dílčí (které se vejdou do limitu příjemců)
182 public void odesli(HromadnaZprava zprava) throws MessagingException {
183 Collection<HromadnaZprava> zpravy = zprava.getDilciZpravy(nastaveni.getLimitZprav());
185 for (HromadnaZprava dilciZprava : zpravy) {
186 odesliSMTP(dilciZprava);
190 private static boolean zkontrolujAdresu(InternetAddressKomu a) {
191 if (a.getTyp() == null) {
192 log.log(Level.WARNING, "Neplatná adresa (typ): {0}", a.getAddress());
196 if (a.getAddress() == null || a.getAddress().length() < 1) {
197 log.log(Level.WARNING, "Neplatná adresa (address): {0}", a.getPersonal());
201 if (!zkontrolujAdresu(a.getAddress())) {
202 log.log(Level.WARNING, "Adresa nevyhovuje regulárnímu výrazu: {0}", a.getAddress());
209 /** Zkontroluje e-mailovou adresu pomocí regulárního výrazu. */
210 public static boolean zkontrolujAdresu(String adresa) {
211 return adresa != null && Pattern.matches(REGULARNI_EMAIL, adresa);
214 /** @return Vrací true, pokud je zpráva v pořádku */
215 private static boolean zkontrolujZpravu(HromadnaZprava z) {
217 if (z.getPrijemci() == null) {
218 log.log(Level.WARNING, "getPrijemci() == null");
222 if (z.getPrijemci().size() < 1) {
223 log.log(Level.WARNING, "getPrijemci().size() < 1");
227 if (z.getOdesilatel() == null) {
228 log.log(Level.WARNING, "getOdesilatel() == null");
232 if (z.getPredmet() == null) {
233 log.log(Level.WARNING, "getPredmet() == null");
240 private static boolean zkontrolujNastaveni(Nastaveni n) {
242 if (n.getPostovniServer() == null || n.getPostovniServer().length() < 1) {
249 /** Slouží k uložení jména a hesla pro SMTP */
250 private static class PostakuvHeslovnik extends Authenticator {
252 private String jmeno = "user";
253 private char[] heslo = "luser".toCharArray();
256 public PasswordAuthentication getPasswordAuthentication() {
257 return new PasswordAuthentication(jmeno, String.valueOf(heslo));
260 public void setJmenoHeslo(String jmeno, char[] heslo) {