All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.gv2011.util.email.imp.DefaultMailProvider Maven / Gradle / Ivy

There is a newer version: 0.12
Show newest version
package com.github.gv2011.util.email.imp;

import static com.github.gv2011.util.CollectionUtils.recursiveStream;
import static com.github.gv2011.util.Equal.equal;
import static com.github.gv2011.util.StringUtils.toLowerCase;
import static com.github.gv2011.util.ex.Exceptions.call;
import static com.github.gv2011.util.ex.Exceptions.callWithCloseable;
import static com.github.gv2011.util.ex.Exceptions.format;
import static com.github.gv2011.util.ex.Exceptions.notYetImplemented;
import static com.github.gv2011.util.icol.ICollections.emptyList;
import static com.github.gv2011.util.icol.ICollections.toIList;
import static java.util.function.Predicate.not;
import static java.util.stream.Collectors.joining;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Date;
import java.util.Properties;
import java.util.function.Consumer;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import com.github.gv2011.util.AutoCloseableNt;
import com.github.gv2011.util.BeanUtils;
import com.github.gv2011.util.StreamUtils;
import com.github.gv2011.util.ann.Nullable;
import com.github.gv2011.util.bytes.DataType;
import com.github.gv2011.util.bytes.DataTypes;
import com.github.gv2011.util.email.Email;
import com.github.gv2011.util.email.EmailAddress;
import com.github.gv2011.util.email.MailAccount;
import com.github.gv2011.util.email.MailProvider;
import com.github.gv2011.util.email.ParsedEmail;
import com.github.gv2011.util.icol.IList;
import com.github.gv2011.util.icol.Opt;

import jakarta.mail.Address;
import jakarta.mail.BodyPart;
import jakarta.mail.Multipart;
import jakarta.mail.Part;
import jakarta.mail.Session;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage;
import jakarta.mail.internet.MimeMessage.RecipientType;
import jakarta.mail.internet.MimeMultipart;
import jakarta.mail.util.ByteArrayDataSource;

public final class DefaultMailProvider implements MailProvider{

  private static final String RFC822 = "rfc822";


  @Override
  public AutoCloseableNt createMailListener(final Consumer mailReceiver, final MailAccount mailAccount) {
    return new MailListener(this, mailReceiver, mailAccount);
  }

  @Override
  public ParsedEmail parse(final Email opaque) {
    return callWithCloseable(opaque.content()::openStream, s->{
      final MimeMessage mime = new MimeMessage(Session.getDefaultInstance(new Properties()), s);
      return BeanUtils.beanBuilder(ParsedEmail.class)
        .set(ParsedEmail::from).to(convert(mime.getFrom()))
        .set(ParsedEmail::replyTo).to(convert(mime.getReplyTo()))
        .set(ParsedEmail::to).to(convert(mime.getRecipients(RecipientType.TO)))
        .set(ParsedEmail::cc).to(convert(mime.getRecipients(RecipientType.CC)))
        .set(ParsedEmail::bcc).to(convert(mime.getRecipients(RecipientType.BCC)))
        .set(ParsedEmail::subject).to(mime.getSubject())
        .set(ParsedEmail::sentDate).to(Opt.ofNullable(mime.getSentDate()).map(Date::toInstant))
        .set(ParsedEmail::receivedDate).to(Opt.ofNullable(mime.getReceivedDate()).map(Date::toInstant))
        .set(ParsedEmail::plainText).to(getPlainText(mime))
        .build()
      ;
    });
  }

  private String getPlainText(final MimeMessage mime) {
    return recursiveStream((Part)mime, m->getChildren(m))
      .filter(p->DataType.parse(call(p::getContentType)).baseType().equals(DataTypes.TEXT_PLAIN))
      .flatMap(p->{
        final DataType dataType = DataType.parse(call(p::getContentType));
        if(!dataType.baseType().equals(DataTypes.TEXT_PLAIN)) {
          return Stream.empty();
        }
        else {
          final Object content = call(p::getContent);
          if(content instanceof String) return Stream.of((String) content);
          else if(content instanceof InputStream) {
            return Stream.of(new String(
              StreamUtils.readAndClose(()->(InputStream)content),
              dataType.charset().orElse(StandardCharsets.UTF_8)
            ));
          }
          else {
            throw new UnsupportedOperationException(format("Unexpected content {}.", content.getClass()));
          }
        }
      })
      .collect(joining("\n ----\n"))
    ;
  }

  private Stream getChildren(final Part m) {
    if(DataType.parse(call(m::getContentType)).baseType().primaryType().equals(DataTypes.MULTIPART)){
      final Object content = call(m::getContent);
      final Multipart multipart;
      if(content instanceof Multipart) {
        multipart = (Multipart) content;
      }
      else if(content instanceof InputStream) {
        multipart = call(()->new MimeMultipart(new ByteArrayDataSource(
          StreamUtils.readAndClose(()->(InputStream)content),
          m.getContentType()
        )));
      }
      else {
        throw new UnsupportedOperationException(format("Unexpected content {}.", content.getClass()));
      }
      return IntStream.range(0, call(multipart::getCount))
        .mapToObj(i->call(()->multipart.getBodyPart(i)))
        .filter(not(this::isAttachment))
      ;
    }
    else return Stream.empty();
  }

  private boolean isAttachment(final BodyPart bodyPart){
    return toLowerCase(call(()->Opt.ofNullable(bodyPart.getDisposition()).orElse(""))).equals("attachment");
  }

  private IList convert(@Nullable final Address[] aa) {
    return aa==null
      ? emptyList()
      : (Arrays.stream(aa)
        .filter(a->equal(a.getType(), RFC822))
        .filter(a->a instanceof InternetAddress)
        .map(a->
          EmailAddress.parse(((InternetAddress)a).getAddress())
        )
        .collect(toIList())
      )
    ;
  }

  @Override
  public ParsedEmail sendEmail(final ParsedEmail email, final MailAccount mailAccount) {
    // TODO Auto-generated method stub
    return notYetImplemented();
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy