Envoyer un mail sans application tierce.

Samedi 24 novembre 2012, 15:44

Bonjour à tous, Aujourd’hui nous allons nous attaquer à l’envoi de mail sans passer par une application tierce. Tout cela sera réalisé avec la librairie JavaMail.

Dans quel cas utiliser cette méthode ?

Plutôt que d’utiliser des applications beaucoup plus optimisées, moi je l’utilise au travail, pour envoyer les crash de mes applications en background (caché de mon utilisateur). Vous allez me dire, il y a bien ACRA, mais il demande une interaction utilisateur, et parfois les personnes ne prennent pas le temps de faire « send report »… 

Il est possible de recevoir/envoyer des mails, ajouter des pièces jointes etc. Très complète comme librairie. Mais je ne vais vous présenter que l’envoi via une petite application très rapide.

Bien entendu, c’est un tuto, beaucoup de tests (adresse mail, etc), de gestion de spam de clique « envoyé » ne sont pas présents.

Nous allons nous pencher légèrement sur la classe Mail, elle défini en gros toutes les options et les paramètres de l’envoi de mail.

public class Mail extends javax.mail.Authenticator {

    private String _user;
    private String _pass;
    private String[] _to;
    private String _from;
    private String _port;
    private String _sport;
    private String _host;
    private String _subject;
    private String _body;
    private boolean _auth;
    private boolean _debuggable;
    private Multipart _multipart;

    public Mail() {
        _host = "smtp.gmail.com";
        _port = "25";
        _sport = "465";
        _subject = "";
        _body = "";
        _debuggable = false;
        _auth = true;
        _multipart = new MimeMultipart();

        MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
        mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
        mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
        mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
        mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");
        mc.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822");
        CommandMap.setDefaultCommandMap(mc);
    }

    public Mail(String user, String pass) {
        this();
        _user = user;
        _pass = pass;
    }

    public boolean send() throws Exception {
        Properties props = _setProperties();
        if (!_user.equals("") && !_pass.equals("") && _to.length > 0 && !_from.equals("") && !_subject.equals("") && !_body.equals("")) {
            Session session = Session.getInstance(props, this);
            Transport transport = session.getTransport("smtp");
            if (!transport.isConnected()) {
                /** ouvre la connexion si elle ne l'est pas faite ! */
                transport.connect(_user, _pass);
            }
            MimeMessage msg = new MimeMessage(session);
            msg.setFrom(new InternetAddress(_from));
            InternetAddress[] addressTo = new InternetAddress[_to.length];
            for (int i = 0; i < _to.length; i++) {
                addressTo[i] = new InternetAddress(_to[i]);
            }
            msg.setRecipients(MimeMessage.RecipientType.TO, addressTo);
            msg.setSubject(_subject);
            msg.setSentDate(new Date());
            BodyPart messageBodyPart = new MimeBodyPart();
            messageBodyPart.setText(_body);
            _multipart.addBodyPart(messageBodyPart);
            msg.setContent(_multipart);
            //   Transport.send(msg);
            transport.sendMessage(msg, msg.getAllRecipients());
            System.out.println("envoyé");
            return true;
        } else {
            return false;
        }
    }

    public void addAttachment(String filename) throws Exception {
        BodyPart messageBodyPart = new MimeBodyPart();
        FileDataSource source = new FileDataSource(filename);
        messageBodyPart.setDataHandler(new DataHandler(source));
        messageBodyPart.setFileName(filename);

        _multipart.addBodyPart(messageBodyPart);
    }

    @Override
    public PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication(_user, _pass);
    }

    private Properties _setProperties() {
        Properties props = new Properties();
        props.put("mail.smtp.host", _host);
        if (_debuggable) {
            props.put("mail.debug", "true");
        }
        if (_auth) {
            props.put("mail.smtp.auth", "true");
        }
        props.put("mail.smtp.port", _port);
        props.put("mail.smtp.socketFactory.port", _sport);
        props.put("mail.smtp.socketFactory.class","javax.net.ssl.SSLSocketFactory");
        props.put("mail.smtp.socketFactory.fallback", "false");
        return props;
    }
//getter and setter
}

Ensuite elle réalise déjà pas mal de test, sur les paramètres obligatoires d’un mail, et renverra faux à l’envoi. Donc elle réalisé déjà le gros de votre travail si vous oubliez des champs… Transport a deux méthodes send. Une send et une autre sendMessage. Il y a une grosse différence entres les deux.

Tout d’abord send() est une static, et dans l’API il est dit « unlike this method »… En plus, juste avant l’appel de l’envoi, nous instancions Transport, pour tester si l’utilisateur (user dans l’app) est bien connecté, si non, il le ferra. Donc autant utiliser la meilleure méthode qui n’appellera pas le saveChanges et donc ira plus vite à l’envoi.

Encore une idée d’apparence de formulaire :D

Ensuite, pour en revenir à l’application tuto, nous réalisons qu’il est très facile d’utilisation la création de mail. N’oubliez pas qu’elle doit être envoyé dans un Thread a part. Sinon l’application freezera jusqu’à ce que l’envoi soit réalisé.

public class TutoSendMail extends Activity implements OnClickListener{

    public Mail m;

    private EditText mailEdit;
    private EditText pwdEdit;
    private EditText toEdit;
    private EditText subjectEdit;
    private Button sendMail;

    private String user;
    private String pwd;
    private String to;
    private String subject;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.tutosendmail_view);

        mailEdit = (EditText) findViewById(R.id.editMail);
        pwdEdit  = (EditText) findViewById(R.id.editMdp);
        toEdit = (EditText) findViewById(R.id.editTo);
        subjectEdit = (EditText) findViewById(R.id.editSubject);
        sendMail = (Button) findViewById(R.id.buttonSend);
        /** surtout pas oublier d'assigner le onclick au bouton */
        sendMail.setOnClickListener(this);
    }

    /**
     * AsyncTask pour envoyer le mail
     * @author fritte
     *
     */
    private class SendMail extends AsyncTask<Void, Void, String[]> {
        private boolean envoye;

        @Override
        protected String[] doInBackground(Void... params) {

            /** user et pwd de qui envoie */
            m = new Mail(user, pwd);
            /** a qui j'envoie */
            String[] toArr = {
                to
            };
            m.set_to(toArr);
            /** le 'from' de qui vient le mail */
            m.set_from(user);
            /** le sujet */
            m.set_subject("Test envoi mail via javamail");
            /** et le message */
            m.set_body(subject);
            try {
                /** l'envoi */
                if (m.send()) {
                    envoye = true;
                } else {
                    envoye = false;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(String[] result) {
            super.onPostExecute(result);
            if (envoye) {
                Crouton.makeText(TutoSendMail.this, getString(R.string.envoye), Style.CONFIRM).show();
            } else {
                Crouton.makeText(TutoSendMail.this, getString(R.string.pasenvoye), Style.ALERT).show();
            }
        }
    }

    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.buttonSend:
                if (testIfNull()) {
                    /** on pourrait même lancer une progressDialogue dans l'action barre, comme pour le refresh G+ etc */
                    new SendMail().execute();
                }
                break;
        }
    }

    /**
     * on peut tester aussi avec un regex les mails s'ils sont correct etc...
     * @return
     */
    private boolean testIfNull() {
        boolean OK;
        if (mailEdit.getText().toString().length() > 0
            && pwdEdit.getText().toString().length() > 0
            && toEdit.getText().toString().length() > 0
            && subjectEdit.getText().toString().length() > 0) {

            user = mailEdit.getText().toString();
            pwd = pwdEdit.getText().toString();
            to = toEdit.getText().toString();
            subject = subjectEdit.getText().toString();
            OK = true;
        } else {
            OK = false;
            Crouton.makeText(TutoSendMail.this, getString(R.string.erreur_champs_vides), Style.ALERT).show();
        }
        return OK;
    }
}

Si vous avez des questions, n’hésitez pas. Voici le lien vers le code source de l’application avec le tutorial d’avant, Crouton et Toast  https://code.google.com/p/fritte-tuto-master/

Mots-clefs :

A propos de l'auteur
Laurent

Développeur Java & mobile, plus particulièrement sur Android, passionné par les technologies mobile et la S-F, je travail pour VLS Henrotte une entreprise basé à Liège. Autodidacte, motivé et surtout très ouvert à tout ce qui approche de l’innovation ou la révolution, je partage mes connaissances ou mes sources. Je suis aussi un twitterfou

Laisser un commentaire

Commentaires

Bonjour! je n’arrive pas à compilé le code avec mon émulateur, est ce que quelqu’un peut m’expliquer pourquoi, ça ne compile pas