본문 바로가기
안드로이드 자바

[Android][Java] Javax로 이메일 전송 기능 구현

by teamnova 2023. 1. 2.

안녕하세요.

오늘은 javax 라이브러리를 사용해 이메일을 전송하는 방법에 대해 알아보겠습니다.

 

시작하기 전에 설정해야될 것들이 몇 가지 있습니다.

 

1. import

activation.jar

additionnal.jar

mail.jar

위 세 개의 파일을 전부 다운로드합니다.

그 후, 아래 사진과 같이 안드로이드 스튜디오의 왼쪽 상단에서 project를 선택합니다.

그 후, 다운로드한 세 개의 파일을 아래 경로에 저장합니다.

그 후 각 jar 파일들을 우클릭을 통해 "Add As Library"를 클릭해 import를 해줍니다.

2. 권한 설정

 

우선 이메일 전송을 위해 Internet permission이 필요하기 때문에 Manifest 파일에 다음 코드를 추가해줍니다.

<uses-permission android:name="android.permission.INTERNET" />

설정은 끝났고 이제 구현에 필요한 클래스 파일들을 만들어줍니다.

 

GMailSender.java

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class GMailSender extends javax.mail.Authenticator {
    private String mailhost = "smtp.gmail.com";
    private String user;
    private String password;
    private Session session;
    private String emailCode;

    public GMailSender(String user, String password) {
        this.user = user;
        this.password = password;
        emailCode = createEmailCode();
        Properties props = new Properties();
        props.setProperty("mail.transport.protocol", "smtp");
        props.setProperty("mail.host", mailhost);
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.port", "465");
        props.put("mail.smtp.socketFactory.port", "465");
        props.put("mail.smtp.socketFactory.class",
                "javax.net.ssl.SSLSocketFactory");
        props.put("mail.smtp.socketFactory.fallback", "false");
        props.setProperty("mail.smtp.quitwait", "false");

        //구글에서 지원하는 smtp 정보를 받아와 MimeMessage 객체에 전달해준다.
        session = Session.getDefaultInstance(props, this);
    }

    public String getEmailCode() {
        return emailCode;
    } //생성된 이메일 인증코드 반환

    private String createEmailCode() { //이메일 인증코드 생성
        String[] str = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
                "t", "u", "v", "w", "x", "y", "z", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
        String newCode = new String();

        for (int x = 0; x < 8; x++) {
            int random = (int) (Math.random() * str.length);
            newCode += str[random];
        }

        return newCode;
    }

    protected PasswordAuthentication getPasswordAuthentication() {
        //해당 메서드에서 사용자의 계정(id & password)을 받아 인증받으며 인증 실패시 기본값으로 반환됨.
        return new PasswordAuthentication(user, password);
    }

    public synchronized void sendMail(String subject, String body, String recipients) throws Exception {
        MimeMessage message = new MimeMessage(session);
        DataHandler handler = new DataHandler(new ByteArrayDataSource(body.getBytes(), "text/plain")); //본문 내용을 byte단위로 쪼개어 전달
        message.setSender(new InternetAddress(user));  //본인 이메일 설정
        message.setSubject(subject); //해당 이메일의 본문 설정
        message.setDataHandler(handler);
        if (recipients.indexOf(',') > 0)
            message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipients));
        else
            message.setRecipient(Message.RecipientType.TO, new InternetAddress(recipients));
        Transport.send(message); //메시지 전달
    }

    public class ByteArrayDataSource implements DataSource {
        private byte[] data;
        private String type;

        public ByteArrayDataSource(byte[] data, String type) {
            super();
            this.data = data;
            this.type = type;
        }

        public ByteArrayDataSource(byte[] data) {
            super();
            this.data = data;
        }

        public void setType(String type) {
            this.type = type;
        }

        public String getContentType() {
            if (type == null)
                return "application/octet-stream";
            else
                return type;
        }

        public InputStream getInputStream() throws IOException {
            return new ByteArrayInputStream(data);
        }

        public String getName() {
            return "ByteArrayDataSource";
        }

        public OutputStream getOutputStream() throws IOException {
            throw new IOException("Not Supported");
        }
    }

}

smtp 연결과 포트 구성을 위한 코드입니다.

이메일 인증코드를 생성하는 부분은 작동이 되지만 해당 게시물에서는 다루지 않고 있기 때문에 사용법을 따로 말씀드리자면, 추후 인증코드를 사용할 액티비티에서 GmailSender 객체를 생성 후, gmailSender.getEmailCode(); 코드를 사용해 String 형태의 인증코드를 가져와서 사용할 수 있습니다.

 

다음으로 SendMail이라는 클래스를 만들어줍니다.

 

SendMail.java

import android.content.Context;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import javax.mail.MessagingException;
import javax.mail.SendFailedException;

public class SendMail extends AppCompatActivity {
    String user = "아이디"; // 보내는 계정의 id
    String password = "비밀번호"; // 보내는 계정의 pw

    GMailSender gMailSender = new GMailSender(user, password);
    String emailCode = gMailSender.getEmailCode();
    public void sendSecurityCode(Context context, String sendTo) {
        try {
            gMailSender.sendMail("제목입니다", "내용입니다", sendTo);
            Toast.makeText(context, "인증번호가 전송되었습니다.", Toast.LENGTH_SHORT).show();
        } catch (SendFailedException e) {
            Toast.makeText(context, "이메일 형식이 잘못되었습니다.", Toast.LENGTH_SHORT).show();
        } catch (MessagingException e) {
            Toast.makeText(context, "인터넷 연결을 확인해주십시오", Toast.LENGTH_SHORT).show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

이제 액티비티에서 SendMail 객체를 생성하면서 생성자를 통해 보내는 계정의 id, pw를 전달해 메일을 보낼 수 있게 됩니다.

여기서 주의해야할 점은 보내는 계정의 비밀번호(pw) 부분을 일반 비밀번호가 아닌 앱 비밀번호라는 것을 입력을 해야합니다. 그 이유 및 앱 비밀번호를 생성하는 방법은 아래와 같습니다.


-> 계정을 안전하게 보호하기 위해 2022년 5월 30일부터 ​​Google은 사용자 이름과 비밀번호만 사용하여 Google 계정에 로그인하도록 요청하는 서드 파티 앱 또는 기기의 사용을 더 이상 지원하지 않습니다.
세부적인 해결 방법은 다음과 같습니다.
 
1. 기존 보내는 메일 서버의 Gmail 계정에 현재 2단계 인증이 걸려 있지 않다면 2단계 인증을 설정하세요. 2단계 인증을 설정하면 보안 수준이 낮은 앱의 액세스가 사용 중지됩니다. 
 
2. 이제 Gmail 계정이 2단계 인증을 사용하기 때문에 안내에 따라 앱 앱 비밀번호를 생성한 후, 비밀번호를 복사하거나 기억해 둡니다. 앱 비밀번호를 생성하려면 직접 다음 페이지로 이동할 수 있습니다. 
https://myaccount.google.com/security?gar=1 (Google에 로그인-> 앱 비밀번호->재로그인)

 

 
보내는 메일 서버: smtp.gmail.com으로 지정하시고, 로그온 정보는 다음과 같이 구성하여 보세요.
  • 사용자 이름: username(at)gmail.com
  • 비밀번호: 앱 비밀번호 (일반 비밀번호가 아님

해당 과정을 통해 이메일을 보낼 Gmail 계정과 그 앱 비밀번호를 코드에 넣어줍니다.

GmailSender의 sendMail 메소드가 매개변수로 메일의 제목, 내용, 받는 계정을 지정합니다.

이제 액티비티에서 이 받는 계정을 매개변수로 전달해주면 해당 계정에 설정한 제목, 내용의 메일이 전송됩니다.

MainActivity.java

import android.os.Bundle;
import android.os.StrictMode;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;



public class MainActivity extends AppCompatActivity {

    Button mailButton = null;
    EditText emailText = null;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                .permitDiskReads()
                .permitDiskWrites()
                .permitNetwork().build());

        mailButton = (Button) findViewById(R.id.mailButton);
        emailText = (EditText) findViewById(R.id.emailTextView);
        mailButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v){
                SendMail mailServer = new SendMail();
                mailServer.sendSecurityCode(getApplicationContext(), emailText.getText().toString());
            }
        });
    }
}

이제 해당 액티비티에 메일을 받을 계정을 입력해준 후, 버튼을 클릭하면 아래와 같은 메일을 전송받게 됩니다.

 

오늘 준비한 내용은 여기까지입니다.

궁금한 점은 언제든 댓글로 남겨주세요.

감사합니다!