Лучший способ отобразить электронную почту (JavaMail Message) в Android - PullRequest
0 голосов
/ 27 апреля 2018

Я создаю почтовое клиентское приложение для Android. Мне удалось отобразить заголовки / отправители писем в RecylerView. Затем я хочу начать новое действие, которое будет отображать содержимое / вложения электронной почты, когда пользователь выбирает конкретную почту.

Мне тяжело делать это через намерения. Я могу получить содержимое письма (текст, встроенные изображения, вложения), но не могу найти способ отобразить их как можно ближе к исходному формату. Я думал о том, чтобы поместить текст в StringBuilder и отправить его через намерение, чтобы отобразить текст, но в этом случае я не могу отобразить встроенные изображения в нужном месте, а также возникают проблемы с форматированием.

Любые указания относительно того, как мне следует подходить к этому, очень ценятся.

Класс, который отображает список доступных писем и получает содержимое определенного письма, чтобы отправить ему другое действие для его отображения. Я знаю, что код немного опасен, я перепробовал много подходов, и он далек от окончательной формы.

public class CheckMail extends Activity {


static List<Message> messages = new ArrayList<>();
String[] sender;
String[] date;
String[] subject;
boolean[] seen;
Context context = null;
ListView listView;
Intent intent;
Store store;
StringBuilder content = new StringBuilder();

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

    setContentView(R.layout.activity_check_mail);
    if (android.os.Build.VERSION.SDK_INT > 9)
    {
        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
        StrictMode.setThreadPolicy(policy);
    }

    context = this;


    ReadEmails task = new ReadEmails();
    task.execute();

}

public void writePart(Part p) throws Exception {
    if (p instanceof Message)
        this.writeEnvelope((Message) p);



    //check if the content is plain text
    if (p.isMimeType("text/plain")) {

      content.append(p.getContent().toString());


    }

    //check if the content has attachment
    else if (p.isMimeType("multipart/*")) {
        System.out.println("This is a Multipart");
        System.out.println("---------------------------");
        Multipart mp = (Multipart) p.getContent();
        int count = mp.getCount();
        for (int i = 0; i < count; i++)
            writePart(mp.getBodyPart(i));
    }

     //check if the content is a nested message
    else if (p.isMimeType("message/rfc822")) {
        System.out.println("This is a Nested Message");
        System.out.println("---------------------------");
        writePart((Part) p.getContent());
    }


    /*
    //check if the content is an inline image
    else if (p.isMimeType("image/jpeg")) {
        System.out.println("--------> image/jpeg");
        Object o = p.getContent();

        InputStream x = (InputStream) o;
        // Construct the required byte array
        System.out.println("x.length = " + x.available());
        while ((i = (int) ((InputStream) x).available()) > 0) {
            int result = (int) (((InputStream) x).read(bArray));
            if (result == -1)
                int i = 0;
            byte[] bArray = new byte[x.available()];

            break;
        }
        FileOutputStream f2 = new FileOutputStream("/tmp/image.jpg");
        f2.write(bArray);
    }
    else if (p.getContentType().contains("image/")) {
        System.out.println("content type" + p.getContentType());
        File f = new File("image" + new Date().getTime() + ".jpg");
        DataOutputStream output = new DataOutputStream(
                new BufferedOutputStream(new FileOutputStream(f)));
        com.sun.mail.util.BASE64DecoderStream test =
                (com.sun.mail.util.BASE64DecoderStream) p
                        .getContent();
        byte[] buffer = new byte[1024];
        int bytesRead;
        while ((bytesRead = test.read(buffer)) != -1) {
            output.write(buffer, 0, bytesRead);
        }
    }
    else {
        Object o = p.getContent();
        if (o instanceof String) {
            System.out.println("This is a string");
            System.out.println("---------------------------");
            System.out.println((String) o);
        }
        else if (o instanceof InputStream) {
            System.out.println("This is just an input stream");
            System.out.println("---------------------------");
            InputStream is = (InputStream) o;
            is = (InputStream) o;
            int c;
            while ((c = is.read()) != -1)
                System.out.write(c);
        }
        else {
            System.out.println("This is an unknown type");
            System.out.println("---------------------------");
            System.out.println(o.toString());
        }
    }

*/

}

public void writeEnvelope(Message m) throws Exception {
    System.out.println("This is the message envelope");
    System.out.println("---------------------------");
    Address[] a;
    StringBuilder sender = new StringBuilder();
    StringBuilder recipients = new StringBuilder();
    String subject = "";

    // FROM
    if ((a = m.getFrom()) != null) {
        for (int j = 0; j < a.length; j++)
            sender.append(a[j].toString());
    }

    // TO
    if ((a = m.getRecipients(Message.RecipientType.TO)) != null) {
        for (int j = 0; j < a.length; j++)
            recipients.append(a[j].toString());
    }

    // SUBJECT
    if (m.getSubject() != null)
        subject = m.getSubject();



    intent.putExtra("Sender", sender.toString());
    intent.putExtra("Recipients", recipients.toString());
    intent.putExtra("Message", subject);
    intent.putExtra("Date", m.getReceivedDate().toString());


}



class ReadEmails extends AsyncTask<String, Void, String> {


    @Override
    protected String doInBackground(String... params) {


        // Create all the needed properties - empty!
        Properties connectionProperties = new Properties();
        // Create the session
        Session session = Session.getDefaultInstance(connectionProperties, null);

        try {
            System.out.print("Connecting to the IMAP server...");
            // Connecting to the server
            // Set the store depending on the parameter flag value
            store = session.getStore("imaps");

            // Set the server depending on the parameter flag value
            String server = "imap.gmail.com";
            store.connect(server, "....@gmail.com", "password");

            System.out.println("done!");

            // Get the Inbox folder
            Folder inbox = store.getFolder("Inbox");

            // Set the mode to the read-only mode
            inbox.open(Folder.READ_ONLY);

            // Get messages
            CheckMail.messages = Arrays.asList(inbox.getMessages());

            System.out.println("Reading messages...");

             sender = new String[messages.size()];
             date = new String[messages.size()];
             subject = new String[messages.size()];
             seen = new boolean[messages.size()];

            for (int i = 0; i < messages.size(); i++) {
                try {
                    Address[] froms = messages.get(i).getFrom();
                    String email = froms == null ? null : ((InternetAddress) froms[0]).getAddress();

                    sender[i] = email;
                    date[i] = messages.get(i).getReceivedDate().toString();
                    subject[i] = messages.get(i).getSubject();


                    Flags flags = messages.get(i).getFlags();
                    Flags.Flag[] sf = flags.getSystemFlags();
                    for (int j = 0; j < sf.length; j++) {
                        if (sf[j] == Flags.Flag.SEEN)
                            seen[i] = true;
                    else
                    seen[i] = false;
                    }


                } catch (MessagingException e) {
                    e.printStackTrace();
                }
            }

            System.out.println("Done reading...");


        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    @Override
    protected void onPostExecute(String result) {

        CustomListAdapter whatever = new CustomListAdapter((Activity) context, sender, date, subject, seen);
        listView = (ListView) findViewById(R.id.listviewID);
        listView.setAdapter(whatever);


        listView.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position,
                                    long id) {

                try {

                    content.delete(0, content.length());
                    intent = new Intent(context, OpenMail.class);
                    writePart(messages.get(position));
                    intent.putExtra("Content", content.toString());
                    startActivity(intent);

                }
                catch (Exception e)
                {e.printStackTrace();}
            }
        });

    }





}
}

1 Ответ

0 голосов
/ 30 апреля 2018

Поскольку никто не ответил ... Я отображаю электронные письма через Javamail в некоторых своих приложениях.

Я думаю, что вы на правильном пути, хороший подход - иметь отдельные действия для списка и средства просмотра. [Или отдельные фрагменты, потому что на планшете вы можете отобразить список и текст на одном экране рядом]

Пара проблем, которые могут возникнуть:

  1. Я бы с осторожностью добавлял содержимое электронной почты в дополнительное для запуска действия и / или фиксировал его в состояние сохраненного экземпляра в действии средства просмотра, поскольку существуют ограничения на размер [Например, 1 МБ для сохраненного состояния экземпляра включено Android 7 +]

  2. Загрузка электронной почты в ASyncTask в упражнении может быть не лучшим подходом. Я не знаю всей цели приложения, но я предполагаю, что это то, что должно быть успешным, ждет ли пользователь или нет? ASyncTask продолжит работу, если они выполнят задание, но будет удерживать контекст активности, вызывая так называемую «временную утечку памяти». Вероятно, лучше всего поместить его в службу и загрузить в отдельном потоке. Однако делать это в упражнении в качестве доказательства концепции вполне разумно ...

  3. Я не думаю, что обход структуры сообщения в активности списка электронной почты - лучший подход. В своих приложениях я загружаю электронную почту в фоновом режиме и фиксирую данные в SQL-DB через ContentProvider. На экране средства просмотра сообщений тело письма извлекается из ContentProvider / SQL-DB с использованием компонента, называемого CursorLoader. Он обрабатывает всю загрузку в фоновом режиме, так что пользовательский интерфейс остается отзывчивым при загрузке больших писем. Но в любом случае я избегаю передачи тела сообщения между действиями.

  4. Во многих электронных письмах есть части HTML (multipart / alternative: text / plain & text / html), поэтому средство просмотра было реализовано как WebView. WebView создавал хорошо выглядящие электронные письма с минимальными усилиями.

  5. Пара разных ошибок при получении почты, позаботьтесь о вызове setPeek (true). Это остановит установленный флаг READ. Это не проблема для GMail, но некоторые IMAP-серверы будут устанавливать этот флаг. Пользователи будут жаловаться, если какое-либо приложение, кроме основного почтового приложения, изменит флаг READ. Также не думайте, что присутствуют какие-либо заголовки, спам-сообщения печально известны тем, что пропускают идентификатор сообщения, тему и другие поля. Наконец, возможно, стоит подумать о реализации аутентификации через OAuth2, которая позволит вашему приложению подключаться к учетной записи пользователя GMail через Javamail без необходимости ввода пароля.

Я не уверен, что что-то из этого действительно помогает, потому что это довольно большая работа, но шаг за шагом ... Ура!

...