Created
May 8, 2017 09:55
-
-
Save demixdn/198ee0455d4a12de247f22ae44b0b73f to your computer and use it in GitHub Desktop.
Send email
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
dependencies { | |
compile 'javax.mail:mail:1.4.7' | |
compile 'javax.activation:activation:1.1.1' | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.os.Handler; | |
import android.os.Looper; | |
import android.support.annotation.NonNull; | |
import android.support.annotation.Nullable; | |
import java.io.UnsupportedEncodingException; | |
import java.util.Properties; | |
import java.util.concurrent.BlockingQueue; | |
import java.util.concurrent.LinkedBlockingQueue; | |
import java.util.concurrent.ThreadFactory; | |
import java.util.concurrent.ThreadPoolExecutor; | |
import java.util.concurrent.TimeUnit; | |
import javax.mail.Message; | |
import javax.mail.MessagingException; | |
import javax.mail.Session; | |
import javax.mail.Transport; | |
import javax.mail.internet.InternetAddress; | |
import javax.mail.internet.MimeMessage; | |
import static android.text.TextUtils.isEmpty; | |
import static android.util.Patterns.EMAIL_ADDRESS; | |
public final class EmailClient implements EmailSubmit { | |
private static final int PROCESSORS = Runtime.getRuntime().availableProcessors(); | |
private static final int SCALE_POOL_SIZE = 4; | |
private static final int INITIAL_POOL_SIZE = PROCESSORS > 1 ? PROCESSORS : 2; | |
private static final int MAX_POOL_SIZE = INITIAL_POOL_SIZE * SCALE_POOL_SIZE; | |
private static final int KEEP_ALIVE_TIME = 15; | |
private static final TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS; | |
private String addressFrom; | |
private String personalName; | |
private String addressTo; | |
private String smtpHost; | |
private int smtpPort; | |
private boolean authEnabled; | |
private String authLogin; | |
private String authPassword; | |
private Callback callback; | |
private String subject; | |
private String message; | |
private ThreadPoolExecutor threadPoolExecutor; | |
private EmailClient() { | |
//private | |
} | |
@Override | |
public boolean submit(@NonNull String subject, @NonNull String message) { | |
Properties properties = getProperties(); | |
// Get the default Session object. | |
Session session = Session.getDefaultInstance(properties); | |
try { | |
MimeMessage mimeMessage = createMessage(subject, message, session); | |
Transport transport = session.getTransport("smtps"); | |
transport.connect(null, properties.getProperty("mail.password")); | |
transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients()); | |
transport.close(); | |
return true; | |
} catch (MessagingException | UnsupportedEncodingException e) { | |
e.printStackTrace(); | |
return false; | |
} | |
} | |
@Override | |
public void submit(@NonNull String subject, @NonNull String message, @Nullable Callback callback) { | |
this.callback = callback; | |
checkNotEmpty(subject); | |
this.subject = subject; | |
checkNotEmpty(message); | |
this.message = message; | |
runOnExecutor(); | |
} | |
private void runOnExecutor() { | |
if (this.threadPoolExecutor == null) { | |
createExecutor(); | |
} | |
this.threadPoolExecutor.execute(new SendEmailTask()); | |
} | |
private void createExecutor() { | |
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(); | |
ThreadFactory threadFactory = new JobThreadFactory(); | |
this.threadPoolExecutor = new ThreadPoolExecutor(INITIAL_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, KEEP_ALIVE_TIME_UNIT, workQueue, threadFactory); | |
} | |
@NonNull | |
private MimeMessage createMessage(@NonNull String subject, @NonNull String content, Session session) throws MessagingException, UnsupportedEncodingException { | |
MimeMessage mimeMessage = new MimeMessage(session); | |
mimeMessage.addHeader("Content-type", "text/plain; charset=UTF-8"); | |
String emailEncoding = "UTF-8"; | |
// Set From: header field of the header. | |
InternetAddress address = isEmpty(personalName) ? new InternetAddress(addressFrom) : new InternetAddress(addressFrom, personalName); | |
mimeMessage.setFrom(address); | |
// Set To: header field of the header. | |
mimeMessage.addRecipient(Message.RecipientType.TO, new InternetAddress(addressTo)); | |
mimeMessage.setSubject(subject, emailEncoding); | |
mimeMessage.setText(content, emailEncoding); | |
mimeMessage.saveChanges(); | |
return mimeMessage; | |
} | |
@NonNull | |
private Properties getProperties() { | |
// Get system properties | |
Properties properties = System.getProperties(); | |
// Setup mail server | |
properties.setProperty("mail.smtps.host", smtpHost); | |
properties.setProperty("mail.smtps.port", String.valueOf(smtpPort)); | |
properties.setProperty("mail.smtps.auth", String.valueOf(authEnabled)); | |
if (authEnabled) { | |
properties.setProperty("mail.user", authLogin); | |
properties.setProperty("mail.password", authPassword); | |
} | |
return properties; | |
} | |
private static void checkArgument(boolean b) { | |
if (!b) { | |
throw new IllegalArgumentException(); | |
} | |
} | |
private static CharSequence checkNotEmpty(CharSequence string) { | |
if (isEmpty(string)) { | |
throw new IllegalArgumentException(); | |
} | |
return string; | |
} | |
private static CharSequence checkNotEmpty(CharSequence string, @Nullable String errorMessage) { | |
if (isEmpty(string)) { | |
throw new IllegalArgumentException(errorMessage); | |
} | |
return string; | |
} | |
static class Builder { | |
private static final String ERROR_AUTH_MESSAGE = "If authentication is enabled, then you must specify a username and password"; | |
private static final String ERROR_EMPTY_MESSAGE = "This argument is required"; | |
@Nullable | |
private String addressFrom; | |
@Nullable | |
private String personalName; | |
@Nullable | |
private String addressTo; | |
@Nullable | |
private String smtpHost; | |
private int smtpPort; | |
private boolean authEnabled; | |
@Nullable | |
private String authLogin; | |
@Nullable | |
private String authPassword; | |
Builder() { | |
} | |
Builder from(@NonNull String addressFrom) { | |
checkNotEmpty(addressFrom); | |
checkArgument(isEmail(addressFrom)); | |
this.addressFrom = addressFrom; | |
return this; | |
} | |
Builder to(@NonNull String addressTo) { | |
checkNotEmpty(addressTo); | |
checkArgument(isEmail(addressTo)); | |
this.addressTo = addressTo; | |
return this; | |
} | |
Builder name(@NonNull String personalName) { | |
checkNotEmpty(personalName); | |
this.personalName = personalName; | |
return this; | |
} | |
Builder smtpHost(@NonNull String smtpHost) { | |
checkNotEmpty(smtpHost); | |
this.smtpHost = smtpHost; | |
return this; | |
} | |
Builder smtpPort(int smtpPort) { | |
checkArgument(smtpPort > 0); | |
this.smtpPort = smtpPort; | |
return this; | |
} | |
Builder authEnabled(boolean authEnabled) { | |
this.authEnabled = authEnabled; | |
return this; | |
} | |
Builder authLogin(@NonNull String authLogin) { | |
checkNotEmpty(authLogin); | |
this.authLogin = authLogin; | |
return this; | |
} | |
Builder authPassword(@NonNull String authPassword) { | |
checkNotEmpty(authPassword); | |
this.authPassword = authPassword; | |
return this; | |
} | |
EmailClient build() { | |
EmailClient ec = new EmailClient(); | |
checkNotEmpty(addressFrom, ERROR_EMPTY_MESSAGE); | |
ec.addressFrom = addressFrom; | |
checkNotEmpty(addressTo, ERROR_EMPTY_MESSAGE); | |
ec.addressTo = addressTo; | |
checkNotEmpty(smtpHost, ERROR_EMPTY_MESSAGE); | |
ec.smtpHost = smtpHost; | |
checkArgument(smtpPort > 0); | |
ec.smtpPort = smtpPort; | |
if (personalName != null) { | |
ec.personalName = personalName; | |
} | |
ec.authEnabled = authEnabled; | |
if (ec.authEnabled && (isEmpty(authLogin) || isEmpty(authPassword))) { | |
throw new IllegalArgumentException(ERROR_AUTH_MESSAGE); | |
} | |
if (ec.authEnabled) { | |
ec.authLogin = authLogin; | |
ec.authPassword = authPassword; | |
} | |
return ec; | |
} | |
private boolean isEmail(String email) { | |
return EMAIL_ADDRESS.matcher(email).matches(); | |
} | |
} | |
private static class JobThreadFactory implements ThreadFactory { | |
private static final String THREAD_NAME = "emailclient-thread-"; | |
private int counter = 0; | |
@Override | |
public Thread newThread(@NonNull Runnable runnable) { | |
return new Thread(runnable, THREAD_NAME + counter++); | |
} | |
} | |
public interface Callback { | |
void onSuccess(); | |
void onFailure(Exception exception); | |
} | |
private class SendEmailTask implements Runnable { | |
@Override | |
public void run() { | |
Handler handler = new Handler(Looper.getMainLooper()); | |
Properties properties = getProperties(); | |
// Get the default Session object. | |
Session session = Session.getDefaultInstance(properties); | |
try { | |
MimeMessage mimeMessage = createMessage(subject, message, session); | |
Transport transport = session.getTransport("smtps"); | |
transport.connect(null, properties.getProperty("mail.password")); | |
transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients()); | |
transport.close(); | |
sendCallbackSuccess(handler); | |
} catch (MessagingException | UnsupportedEncodingException e) { | |
e.printStackTrace(); | |
sendCallbackFailure(handler, e); | |
} | |
} | |
private void sendCallbackSuccess(Handler handler) { | |
handler.post(new Runnable() { | |
@Override | |
public void run() { | |
if (EmailClient.this.callback != null) { | |
EmailClient.this.callback.onSuccess(); | |
} | |
} | |
}); | |
} | |
private void sendCallbackFailure(Handler handler, final Exception e) { | |
handler.post(new Runnable() { | |
@Override | |
public void run() { | |
if (EmailClient.this.callback != null) { | |
EmailClient.this.callback.onFailure(e); | |
} | |
} | |
}); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.accounts.NetworkErrorException; | |
import android.os.Handler; | |
import android.os.Looper; | |
import android.support.annotation.NonNull; | |
import java.util.Random; | |
public final class EmailSender { | |
private static final String ADDRESS_FROM = "<email_from>"; | |
private static final String ADDRESS_TO = "<email_to>"; | |
private static final String SMTP_HOST = "<smtp_host>"; | |
private static final int SMTP_PORT = 465; | |
private static final boolean AUTH_ENABLED = true; | |
private static final String AUTH_LOGIN = "<auth_login>"; | |
private static final String AUTH_PASSW = "<auth_password>"; | |
private static final int FAKE_DELAYED = 800; | |
private static final String SUBJECT = "your subject"; | |
private final EmailSubmit emailSubmit; | |
public EmailSender() { | |
EmailClient.Builder builder = new EmailClient.Builder().from(ADDRESS_FROM) | |
.to(ADDRESS_TO) | |
.smtpHost(SMTP_HOST) | |
.smtpPort(SMTP_PORT) | |
.authEnabled(AUTH_ENABLED) | |
.authLogin(AUTH_LOGIN) | |
.authPassword(AUTH_PASSW); | |
emailSubmit = builder.build(); | |
} | |
public final void sendCallback(@NonNull String message, @NonNull EmailClient.Callback callback){ | |
emailSubmit.submit(SUBJECT, message, callback); | |
} | |
/** | |
* Use only for testing | |
* @param callback callback | |
* @deprecated only for test | |
*/ | |
@SuppressWarnings("unused") | |
@Deprecated | |
private void fakeSend(final EmailClient.Callback callback) { | |
Handler handler = new Handler(Looper.getMainLooper()); | |
handler.postDelayed(new Runnable() { | |
@Override | |
public void run() { | |
Random random = new Random(); | |
boolean nextBoolean = random.nextBoolean(); | |
if (nextBoolean) { | |
callback.onSuccess(); | |
} else { | |
callback.onFailure(new NetworkErrorException("wifi is enabled")); | |
} | |
} | |
}, FAKE_DELAYED); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.support.annotation.NonNull; | |
import android.support.annotation.Nullable; | |
import android.support.annotation.UiThread; | |
import android.support.annotation.WorkerThread; | |
public interface EmailSubmit { | |
@WorkerThread | |
boolean submit(@NonNull String subject, @NonNull String message); | |
@UiThread | |
void submit(@NonNull String subject, @NonNull String message, @Nullable EmailClient.Callback callback); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment