Java™ - Cara Download Lampiran pada Email dan Mengekstraknya Kembali via SMTPS Gmail

in utopian-io •  7 years ago  (edited)

What Will I Learn?

Apa Yang Akan Saya Pelajari?

Pada tutorial kali ini, spesial dalam bahasa Indonesia, saya akan menjelaskan bagaimana cara membaca email pada suatu akun Google yang Anda miliki menggunakan program Java™. Selanjutnya, jika di dalam email itu ada lampiran berupa berkas zip, maka kita akan mengekstraknya ke direktori target yang telah ditentukan sebelumnya. Tetapi, sebelum Anda bisa mengikuti tutorial kali ini dengan baik, Anda harus menguasai tutorial sebelumnya yang terlampir pada Curriculum. Berikut adalah materi umum yang akan terkuasai dalam mengikuti tutorial ini.


Requirements

Persyaratan

Pastikan Anda memasang (instalasi) perangkat lunak dan menyesuaikan pengaturan berikut:


Difficulty

Tingkat Kesulitan
  • Basic

    Dasar


Tutorial Contents

  1. Koneksi ke Folder Inbox

    Definisikan properti untuk mendapatkan koneksi ke server melalui SMTPS Gmail pada variabel statik GMAIL, seperti alamat host, port dan lainnya. Kemudian, buat sebuah metode dengan nama retrieve, yang akan menerima dua buah parameter, yaitu username dan password dari akun yang akan dilihat seluruh email-nya.

    Berikut adalah kode untuk mengambil dan membaca semua email sekaligus yang ada di folder Inbox:

    
       public static void retrieve(String username, String password) {
           Session session = Session.getDefaultInstance(GMAIL);
           try {
               Store store = session.getStore("imaps");
               store.connect(GMAIL.getProperty("mail.smtp.host"), username, password);
               Folder inbox = store.getFolder("Inbox");
               inbox.open(Folder.READ_ONLY);
               /*
                * Right now, the folder is ready
                */
               {
                   inbox.getMessages();
               }
               inbox.close(false);
               store.close();
           }
           catch(Throwable e) { e.printStackTrace(); }
       }
       
    private static final java.util.Properties GMAIL = new java.util.Properties();
    static { GMAIL.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); GMAIL.put("mail.smtp.socketFactory.port", "465"); GMAIL.put("mail.smtp.ssl.enable", "true"); GMAIL.put("mail.smtp.auth", "true"); GMAIL.put("mail.smtp.host", "smtp.gmail.com"); GMAIL.put("mail.smtp.port", "465"); }
  2. Membaca Input dari Pengguna

    Program akan terus mengambil dan membaca email dari akun target sampai pengguna memberikan input 0 (nol). Di sini akan digunakan kelas java.io.BufferedReader untuk membaca setiap input sebagai baris dari pengguna melalui konsol. Cara menciptakan objek pembaca input adalah:

    BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)`.
    

    Selanjutnya, jika pengguna memberikan input angka apa pun, maka program pembaca email ini akan melewatkan beberapa email yang akan dibaca sebanyak angka yang diberikan. Maka, kode di atas akan menjadi seperti berikut:

    public static void retrieve(String username, String password) {
        Session session = Session.getDefaultInstance(GMAIL);
        try {
            Store store = session.getStore("imaps");
            store.connect(GMAIL.getProperty("mail.smtp.host"), username, password);
            Folder inbox = store.getFolder("Inbox");
            inbox.open(Folder.READ_ONLY);
            String line;
            int i = 0, n = inbox.getMessageCount();
            try(BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) {
                do {
                    print(inbox.getMessage(n -= (i + 1)));
                    System.out.print("To stop, type \"0\" (zero) or type any positive number to jump: ");
                    line = reader.readLine();
                    try{ i = Integer.parseInt(line); }
                    catch(Throwable e) { i = 0; }
                }
                while(!line.equals("0"));
            }
            inbox.close(false);
            store.close();
        }
        catch(Throwable e) { e.printStackTrace(); }
    }
    
  3. Daftarkan Fungsi Baru untuk Menangani Berkas Zip

    Pada tutorial sebelumnya, kita telah mendaftarkan tiga fungsi untuk menangani berkas dengan tipe multipart/*, gambar dan selain itu semua. Maka akan ditambahkan sebuah fungsi lagi untuk menangani berkas zip.

    • Periksa MimeType

      Tambahkan sebuah variabel statik ZIP untuk menyimpan konstanta application/zip dan pada metode print(Part) selalu periksa tipe dari konten, jika sesuai dengan ZIP atau application/x-rar-compressed lakukan proses ekstraksi. Berikut adalah logikanya:

    private static final Map<String, Function<Object, Void>> FUNCTIONS = new java.util.HashMap<>();
    private static final String ZIP = "application/zip";
    
    . . .
    else if(part.isMimeType(ZIP) || part.isMimeType("application/x-rar-compressed"))
             FUNCTIONS.get(ZIP).apply(part);
    . . .
    
    • Fungsi Ekstraksi Berkas Zip

      Tambahkan kode berikut:

      FUNCTIONS.put(ZIP, content -> {
          BodyPart body;
          Path newSrc, parent;
          InputStream in;
          FileOutputStream out;
          try {
              /*
               * Selalu minta ke pengguna di direktori mana berkas akan disimpan dan diekstrak
               */
              BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
              body = (BodyPart) content;
              System.out.print("Enter path and file name for attachment \"" + body.getFileName() + "\": ");
              newSrc = Paths.get(reader.readLine());
              parent = newSrc.getParent();
              /*
               * Selalu periksa dan buatkan direktori baru jika pengguna
               * memberikan direktori yang tidak pernah ada.
               */
              if(Files.notExists(parent))
                  Files.createDirectories(parent);
              out = new FileOutputStream(newSrc.toFile());
               in = body.getInputStream();
          } catch(Throwable e) {
              e.printStackTrace();
              return null;
          }
          final byte[] BYTES = new byte[2048];
          try {
              /*
               * Proses download
               */
              for(int length;(length = in.read(BYTES)) > -1;)
                  out.write(BYTES, 0, length);
              out.close();
              System.out.println("Download attachment was successful");
              /**
               * Proses ekstraksi berkas yang telah selesai ter-download
               */
              ZipIOStream.unzip(true, parent, newSrc);
              System.out.println("Extraction of " + newSrc + " was successful");
          } catch(Throwable e) {
              e.printStackTrace();
          }
          return null;
      });
      

    Untitled 004.png

  4. Definisikan Metode Ekstraksi

    Pada kelas ZipIOStream yang telah terdefinisikan sebelumnya di sini, buat sebuah metode privat baru dengan nama unzip yang akan menerima parameter java.util.zip.ZipInputStream sebagai zipIn, dan java.nio.file.Path sebagai direktori target. Dan berikut ini adalah kodenya:

    private static void unzip(ZipInputStream zipIn, Path target) throws Throwable {
        ZipEntry entry = zipIn.getNextEntry();
        final byte[] BYTES = new byte[2048];
        for(Path newPath, parent; entry != null; entry = zipIn.getNextEntry()) {
            String name = entry.getName();
            newPath = target.resolve(name);
            if(entry.isDirectory() || name.charAt(name.length() - 1) == separatorChar)
                Files.createDirectories(newPath);
            else {
                if(Files.notExists(parent = newPath.getParent()))
                    Files.createDirectories(parent);
                Files.createFile(newPath);
                try(FileOutputStream out = new FileOutputStream(newPath.toFile());
                    FileLock lock = out.getChannel().lock()) {
                    for(int length; (length = zipIn.read(BYTES)) > -1; )
                        out.write(BYTES, 0, length);
                    lock.release();
                }
            }
        }
    }
    

    Metode di atas hanya dapat mengekstrak sebuah berkas zip, karena hal ini metode tersebut didefinisikan privat. Selanjutnya kita akan mendefinisikan sebuah metode global yang akan dapat mengekstrak banyak berkas sekaligus. Berikut adalah kodenya:

    /**
     * Mengekstrak berkas zip.
     * @param thrown - Apakah akan melemparkan Exception jika terjadi kesalahan, atau tidak.
     * @param target - Direktori target di mana hasil ekstraksi akan dimuat.
     * @param source - Berkas-berkas zip yang akan diekstrak.
     * @return - {@code True} jika proses ekstraksi berhasil, sebaliknya {@code false}.
     */
    public static boolean unzip(boolean thrown, Path target, Path... source) {
        if(Files.notExists(target))
            try {
                Files.createDirectories(target);
            } catch(Throwable e) {
                if(thrown) throw new RuntimeException(e);
                return false;
            }
        else if(Files.isRegularFile(target))
            target = target.getParent();
        boolean b = true;
        for(Path p : source)
            try(ZipInputStream reader = new ZipInputStream(new FileInputStream(p.toFile()))) {
                unzip(reader, target);
            } catch(Throwable e) {
                if(thrown) throw new RuntimeException(e);
                b = false;
            }
        return b;
    }
    

    Untitled 005.png

Pengujian

Pengujian ini masih menggunakan metode Main yang sama seperti sebelumnya.

Email Target

Berikut adalah email target yang akan dibaca kontennya, di-download (Test.zip), dan akhirnya diekstrak.
Untitled 006.png

Log

Untitled 002.png

Hasil

Untitled 003.png

Selamat! Akhirnya kita berhasil men-download berkas zip dan mengekstraknya kembali, serta menyelesaikan tutorial ini dengan baik.

Terima Kasih!

Share with Heart.


Curriculum



Posted on Utopian.io - Rewarding Open Source Contributors

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

Your contribution cannot be approved because it does not follow the Utopian Rules.

You have already shared this post in another language. This is a duplicate.

You can contact us on Discord.
[utopian-moderator]

Hello @deathwing,

You did not actually review my contribution in detail.
This is a series in order to manipulate email in Java apps, and now about retrieving and unzipping.
But you've said that it was duplicate in another language.