1 package cz.frantovo.postak;
4 import java.util.ArrayList;
5 import java.util.Collection;
6 import java.util.Properties;
7 import java.util.logging.Level;
8 import java.util.logging.Logger;
9 import java.util.regex.Pattern;
10 import javax.mail.Address;
11 import javax.mail.Authenticator;
12 import javax.mail.MessagingException;
13 import javax.mail.PasswordAuthentication;
14 import javax.mail.Session;
15 import javax.mail.Transport;
16 import javax.mail.internet.MimeMessage;
19 * Odešle hromadnou zprávu pomocí SMTP.
25 private static Logger log = Logger.getLogger(Postak.class.getName());
26 /** Regulární výraz pro správnou e-mailovou adresu */
27 private static String REGULARNI_EMAIL = "^[_a-zA-Z0-9\\.\\-]+@[_a-zA-Z0-9\\.\\-]+\\.[a-zA-Z]{2,4}$";
29 private Nastaveni nastaveni;
31 public Postak(Nastaveni nastaveni) {
32 this.nastaveni = nastaveni;
35 public void setNastaveni(Nastaveni nastaveni) {
36 this.nastaveni = nastaveni;
40 * Nízkoúrovňová odesílací metoda, která už nekontroluje limit příjemců.
41 * Pokud se nevejdou do limitu SMTP serveru, vyhazuje výjimku.
43 * TODO: lepší to bude nestaické - nastavení si vyžádat v konstruktoru
45 private void odesliSMTP(HromadnaZprava zprava) throws MessagingException {
47 if (zkontrolujZpravu(zprava) && zkontrolujNastaveni(nastaveni)) {
49 /** Inicializace SMTP */
50 Properties smtpVlastnosti = System.getProperties();
51 smtpVlastnosti.put("mail.smtp.host", nastaveni.getPostovniServer());
52 smtpVlastnosti.put("mail.smtp.port", String.valueOf(nastaveni.getPostovniPort()));
54 if (nastaveni.getPostovniPort() == 465) {
55 if (new File(nastaveni.getCestaKCertifikatum()).exists()) {
56 System.setProperty("javax.net.ssl.trustStore", nastaveni.getCestaKCertifikatum());
57 log.log(Level.INFO, "Používám vlastní důvěryhodné certifikáty: " + nastaveni.getCestaKCertifikatum());
59 /** TODO: neřídit se číslem portu, ale přidat příznak pro šifrování */
60 smtpVlastnosti.put("mail.smtp.starttls.enable", "true");
61 smtpVlastnosti.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
62 smtpVlastnosti.put("mail.smtp.socketFactory.port", String.valueOf(nastaveni.getPostovniPort()));
63 smtpVlastnosti.put("mail.smtp.socketFactory.fallback", "false");
65 * NAHRÁNÍ CERTIFIKÁTU:
66 * 1) stáhneme si certifikát (---BEGIN CERTIFICATE---) a uložíme do vse_ca.cer
67 * 2) keytool -importcert -file vse_ca.cer -keystore DuveryhodneCertifikaty.keystore -storepass "changeit"
68 * Pokud daný soubor existuje, program ho používá, pokud ne, používá certifikáty uložené v systému (Javovské).
72 PostakuvHeslovnik heslovnik = new PostakuvHeslovnik();
73 if (nastaveni.getPostovniJmeno() != null && nastaveni.getPostovniJmeno().length() > 0) {
74 heslovnik.setJmenoHeslo(nastaveni.getPostovniJmeno(), nastaveni.getPostovniHeslo());
75 smtpVlastnosti.put("mail.smtp.auth", "true");
76 log.log(Level.FINEST, "Používám pro SMTP jméno a heslo");
79 Session smtpRelace = Session.getInstance(smtpVlastnosti, heslovnik);
81 smtpRelace.setDebug(true);
82 smtpRelace.setDebugOut(System.out);
84 /** Sestavení zprávy */
85 MimeMessage mimeZprava = new MimeMessage(smtpRelace);
86 mimeZprava.setFrom(zprava.getOdesilatel());
87 if (zprava.getOdpovedetKomu() != null) {
88 Address[] odpovedetKomu = {zprava.getOdpovedetKomu()};
89 mimeZprava.setReplyTo(odpovedetKomu);
91 naplnPrijemce(mimeZprava, zprava);
92 mimeZprava.setSubject(zprava.getPredmet());
93 mimeZprava.setHeader("User-Agent", "http://frantovo.cz/projekty/SuperPostak/ | https://posta.veverka.ch/posta/");
94 if (zprava.isFormatHTML()) {
95 mimeZprava.setText(zprava.getText(), "UTF-8", "html");
97 mimeZprava.setText(zprava.getText(), "UTF-8");
100 /** Vlastní odeslání */
101 Transport.send(mimeZprava);
104 MessagingException e = new MessagingException("Zpráva nebo nastavení jsou nevyhovující");
105 log.log(Level.SEVERE, null, e);
112 * Nastaví zprávě (MimeMessage) všechny příjemce, které najde ve zprávě a nastavení.
113 * Respektuje typy příjemců: komu, kopie, skrytá kopie.
115 private static void naplnPrijemce(MimeMessage mimeZprava, HromadnaZprava zprava) throws MessagingException {
117 * Příjemci se budou definovat pouze ve zprávě.
118 * Z nastavení se brát nebudou (výchozí příjemci už ve zprávě budou).
120 ArrayList<InternetAddressKomu> prijemci = zprava.getPrijemci();
121 for (InternetAddressKomu komu : prijemci) {
122 if (zkontrolujAdresu(komu)) {
123 mimeZprava.addRecipient(komu.getTyp(), komu);
128 /** Vypíše do logu seznam příjemců */
129 public static void vypisPrijemce(Collection<InternetAddressKomu> prijemci) {
130 for (InternetAddressKomu p : prijemci) {
131 log.log(Level.INFO, p.toString());
135 /** Veřejná odesílací metoda.
136 * Postará se o rozdělení zpráv na dílčí (které se vejdou do limitu příjemců)
138 public void odesli(HromadnaZprava zprava) throws MessagingException {
139 Collection<HromadnaZprava> zpravy = zprava.getDilciZpravy(nastaveni.getLimitZprav());
141 for (HromadnaZprava dilciZprava : zpravy) {
142 odesliSMTP(dilciZprava);
146 private static boolean zkontrolujAdresu(InternetAddressKomu a) {
147 if (a.getTyp() == null) {
148 log.log(Level.WARNING, "Neplatná adresa (typ): " + a.getAddress());
152 if (a.getAddress() == null || a.getAddress().length() < 1) {
153 log.log(Level.WARNING, "Neplatná adresa (address): " + a.getPersonal());
157 if (!zkontrolujAdresu(a.getAddress())) {
158 log.log(Level.WARNING, "Adresa nevyhovuje regulárnímu výrazu: " + a.getAddress());
165 /** Zkontroluje e-mailovou adresu pomocí regulárního výrazu. */
166 public static boolean zkontrolujAdresu(String adresa) {
167 return adresa != null && Pattern.matches(REGULARNI_EMAIL, adresa);
170 /** @return Vrací true, pokud je zpráva v pořádku */
171 private static boolean zkontrolujZpravu(HromadnaZprava z) {
173 if (z.getPrijemci() == null) {
174 log.log(Level.WARNING, "getPrijemci() == null");
178 if (z.getPrijemci().size() < 1) {
179 log.log(Level.WARNING, "getPrijemci().size() < 1");
183 if (z.getOdesilatel() == null) {
184 log.log(Level.WARNING, "getOdesilatel() == null");
188 if (z.getPredmet() == null) {
189 log.log(Level.WARNING, "getPredmet() == null");
196 private static boolean zkontrolujNastaveni(Nastaveni n) {
198 if (n.getPostovniServer() == null || n.getPostovniServer().length() < 1) {
205 /** Slouží k uložení jména a hesla pro SMTP */
206 private static class PostakuvHeslovnik extends Authenticator {
208 private String jmeno = "user";
209 private char[] heslo = "luser".toCharArray();
212 public PasswordAuthentication getPasswordAuthentication() {
213 return new PasswordAuthentication(jmeno, String.valueOf(heslo));
216 public void setJmenoHeslo(String jmeno, char[] heslo) {