killbill-aplcache

util: Initial reap-off of email service inside Kill Bill. See

9/15/2017 5:43:21 PM

Changes

api/src/main/java/org/killbill/billing/invoice/api/InvoiceNotifier.java 25(+0 -25)

api/src/main/java/org/killbill/billing/overdue/applicator/formatters/OverdueEmailFormatterFactory.java 24(+0 -24)

api/src/main/java/org/killbill/billing/util/email/EmailApiException.java 36(+0 -36)

api/src/main/java/org/killbill/billing/util/email/EmailSender.java 27(+0 -27)

invoice/src/main/java/org/killbill/billing/invoice/notification/EmailInvoiceNotifier.java 118(+0 -118)

invoice/src/main/java/org/killbill/billing/invoice/notification/NullInvoiceNotifier.java 30(+0 -30)

jaxrs/src/main/java/org/killbill/billing/jaxrs/mappers/EmailApiExceptionMapper.java 42(+0 -42)

overdue/src/main/java/org/killbill/billing/overdue/applicator/formatters/DefaultOverdueEmailFormatterFactory.java 27(+0 -27)

overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueEmailGenerator.java 60(+0 -60)

util/src/main/java/org/killbill/billing/util/email/DefaultEmailSender.java 98(+0 -98)

util/src/main/java/org/killbill/billing/util/email/EmailConfig.java 67(+0 -67)

util/src/main/java/org/killbill/billing/util/email/EmailModule.java 40(+0 -40)

util/src/test/java/org/killbill/billing/util/email/EmailSenderTest.java 49(+0 -49)

Details

diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/BeatrixIntegrationModule.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/BeatrixIntegrationModule.java
index 5b501ad..0fae546 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/BeatrixIntegrationModule.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/BeatrixIntegrationModule.java
@@ -46,7 +46,6 @@ import org.killbill.billing.tenant.glue.DefaultTenantModule;
 import org.killbill.billing.usage.glue.UsageModule;
 import org.killbill.billing.util.config.definition.InvoiceConfig;
 import org.killbill.billing.util.config.definition.PaymentConfig;
-import org.killbill.billing.util.email.EmailModule;
 import org.killbill.billing.util.email.templates.TemplateModule;
 import org.killbill.billing.util.glue.AuditModule;
 import org.killbill.billing.util.glue.BroadcastModule;
@@ -88,7 +87,6 @@ public class BeatrixIntegrationModule extends KillBillModule {
         install(new GlobalLockerModule(configSource));
         install(new CacheModule(configSource));
         install(new ConfigModule(configSource));
-        install(new EmailModule(configSource));
         install(new CallContextModule(configSource));
         install(new TagStoreModule(configSource));
         install(new CustomFieldModule(configSource));
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/glue/DefaultInvoiceModule.java b/invoice/src/main/java/org/killbill/billing/invoice/glue/DefaultInvoiceModule.java
index d400a3f..2fc4a1f 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/glue/DefaultInvoiceModule.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/glue/DefaultInvoiceModule.java
@@ -26,7 +26,6 @@ import org.killbill.billing.invoice.ParkedAccountsManager;
 import org.killbill.billing.invoice.api.DefaultInvoiceService;
 import org.killbill.billing.invoice.api.InvoiceApiHelper;
 import org.killbill.billing.invoice.api.InvoiceInternalApi;
-import org.killbill.billing.invoice.api.InvoiceNotifier;
 import org.killbill.billing.invoice.api.InvoicePaymentApi;
 import org.killbill.billing.invoice.api.InvoiceService;
 import org.killbill.billing.invoice.api.InvoiceUserApi;
@@ -46,10 +45,8 @@ import org.killbill.billing.invoice.generator.InvoiceGenerator;
 import org.killbill.billing.invoice.generator.UsageInvoiceItemGenerator;
 import org.killbill.billing.invoice.notification.DefaultNextBillingDateNotifier;
 import org.killbill.billing.invoice.notification.DefaultNextBillingDatePoster;
-import org.killbill.billing.invoice.notification.EmailInvoiceNotifier;
 import org.killbill.billing.invoice.notification.NextBillingDateNotifier;
 import org.killbill.billing.invoice.notification.NextBillingDatePoster;
-import org.killbill.billing.invoice.notification.NullInvoiceNotifier;
 import org.killbill.billing.invoice.plugin.api.InvoicePluginApi;
 import org.killbill.billing.invoice.template.bundles.DefaultResourceBundleFactory;
 import org.killbill.billing.invoice.usage.RawUsageOptimizer;
@@ -119,14 +116,6 @@ public class DefaultInvoiceModule extends KillBillModule implements InvoiceModul
         bind(InvoiceFormatterFactory.class).to(config.getInvoiceFormatterFactoryClass()).asEagerSingleton();
     }
 
-    protected void installInvoiceNotifier() {
-        if (staticInvoiceConfig.isEmailNotificationsEnabled()) {
-            bind(InvoiceNotifier.class).to(EmailInvoiceNotifier.class).asEagerSingleton();
-        } else {
-            bind(InvoiceNotifier.class).to(NullInvoiceNotifier.class).asEagerSingleton();
-        }
-    }
-
     protected void installInvoiceDispatcher() {
         bind(InvoiceDispatcher.class).asEagerSingleton();
     }
@@ -155,7 +144,6 @@ public class DefaultInvoiceModule extends KillBillModule implements InvoiceModul
 
         installInvoicePluginApi();
         installInvoiceService();
-        installInvoiceNotifier();
         installNotifiers();
         installInvoiceDispatcher();
         installInvoiceListener();
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
index 4f274ba..2d547ac 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
@@ -61,7 +61,6 @@ import org.killbill.billing.invoice.api.Invoice;
 import org.killbill.billing.invoice.api.InvoiceApiException;
 import org.killbill.billing.invoice.api.InvoiceItem;
 import org.killbill.billing.invoice.api.InvoiceItemType;
-import org.killbill.billing.invoice.api.InvoiceNotifier;
 import org.killbill.billing.invoice.api.InvoiceStatus;
 import org.killbill.billing.invoice.api.user.DefaultInvoiceNotificationInternalEvent;
 import org.killbill.billing.invoice.api.user.DefaultNullInvoiceEvent;
@@ -134,7 +133,6 @@ public class InvoiceDispatcher {
     private final SubscriptionBaseInternalApi subscriptionApi;
     private final InvoiceDao invoiceDao;
     private final InternalCallContextFactory internalCallContextFactory;
-    private final InvoiceNotifier invoiceNotifier;
     private final InvoicePluginDispatcher invoicePluginDispatcher;
     private final GlobalLocker locker;
     private final PersistentBus eventBus;
@@ -150,7 +148,6 @@ public class InvoiceDispatcher {
                              final SubscriptionBaseInternalApi SubscriptionApi,
                              final InvoiceDao invoiceDao,
                              final InternalCallContextFactory internalCallContextFactory,
-                             final InvoiceNotifier invoiceNotifier,
                              final InvoicePluginDispatcher invoicePluginDispatcher,
                              final GlobalLocker locker,
                              final PersistentBus eventBus,
@@ -164,7 +161,6 @@ public class InvoiceDispatcher {
         this.accountApi = accountApi;
         this.invoiceDao = invoiceDao;
         this.internalCallContextFactory = internalCallContextFactory;
-        this.invoiceNotifier = invoiceNotifier;
         this.invoicePluginDispatcher = invoicePluginDispatcher;
         this.locker = locker;
         this.eventBus = eventBus;
@@ -210,7 +206,7 @@ public class InvoiceDispatcher {
             return processAccountFromNotificationOrBusEvent(accountId, targetDate, dryRunArguments, context);
         } catch (final SubscriptionBaseApiException e) {
             log.warn("Failed handling SubscriptionBase change.",
-                      new InvoiceApiException(ErrorCode.INVOICE_NO_ACCOUNT_ID_FOR_SUBSCRIPTION_ID, subscriptionId.toString()));
+                     new InvoiceApiException(ErrorCode.INVOICE_NO_ACCOUNT_ID_FOR_SUBSCRIPTION_ID, subscriptionId.toString()));
             return null;
         }
     }
@@ -386,7 +382,7 @@ public class InvoiceDispatcher {
             final UUID targetInvoiceId;
             if (billingEvents.isAccountAutoInvoiceReuseDraft()) {
                 final InvoiceModelDao earliestDraftInvoice = invoiceDao.getEarliestDraftInvoiceByAccount(context);
-                targetInvoiceId = earliestDraftInvoice != null  ? earliestDraftInvoice.getId() : null;
+                targetInvoiceId = earliestDraftInvoice != null ? earliestDraftInvoice.getId() : null;
             } else {
                 targetInvoiceId = null;
             }
@@ -463,10 +459,6 @@ public class InvoiceDispatcher {
 
                 setChargedThroughDates(invoice.getInvoiceItems(FixedPriceInvoiceItem.class), invoice.getInvoiceItems(RecurringInvoiceItem.class), context);
 
-                if (InvoiceStatus.COMMITTED.equals(invoice.getStatus())) {
-                    notifyAccountIfEnabled(account, invoice, isRealInvoiceWithNonEmptyItems, context);
-                }
-
             }
             return invoice;
         } catch (final AccountApiException e) {
@@ -522,12 +514,12 @@ public class InvoiceDispatcher {
 
     private List<InvoiceItemModelDao> transformToInvoiceModelDao(final List<InvoiceItem> invoiceItems) {
         return Lists.transform(invoiceItems,
-                                   new Function<InvoiceItem, InvoiceItemModelDao>() {
-                                       @Override
-                                       public InvoiceItemModelDao apply(final InvoiceItem input) {
-                                           return new InvoiceItemModelDao(input);
-                                       }
-                                   });
+                               new Function<InvoiceItem, InvoiceItemModelDao>() {
+                                   @Override
+                                   public InvoiceItemModelDao apply(final InvoiceItem input) {
+                                       return new InvoiceItemModelDao(input);
+                                   }
+                               });
     }
 
     private Set<UUID> getUniqueInvoiceIds(final Invoice invoice) {
@@ -570,18 +562,6 @@ public class InvoiceDispatcher {
         return isThereAnyItemsLeft;
     }
 
-    private void notifyAccountIfEnabled(final ImmutableAccountData account, final Invoice invoice, final boolean isRealInvoiceWithNonEmptyItems, final InternalCallContext context) throws InvoiceApiException, AccountApiException {
-        // Ideally we would retrieve the cached version, all the invoice code has been modified to only use ImmutableAccountData, except for the
-        // isNotifiedForInvoice piece that should probably live outside of invoice code anyways... (see https://github.com/killbill/killbill-email-notifications-plugin)
-        final Account fullAccount = accountApi.getAccountById(account.getId(), context);
-
-        if (fullAccount.isNotifiedForInvoices() && isRealInvoiceWithNonEmptyItems) {
-            // Need to re-hydrate the invoice object to get the invoice number (record id)
-            // API_FIX InvoiceNotifier public API?
-            invoiceNotifier.notify(fullAccount, new DefaultInvoice(invoiceDao.getById(invoice.getId(), context)), buildTenantContext(context));
-        }
-    }
-
     private InvoiceItem computeCBAOnExistingInvoice(final Invoice invoice, final InternalCallContext context) throws InvoiceApiException {
         // Transformation to Invoice -> InvoiceModelDao
         final InvoiceModelDao invoiceModelDao = new InvoiceModelDao(invoice);
@@ -835,14 +815,17 @@ public class InvoiceDispatcher {
     private boolean shouldIgnoreChildInvoice(final Invoice childInvoice, final BigDecimal childInvoiceAmount) {
 
         switch (childInvoiceAmount.compareTo(BigDecimal.ZERO)) {
-            case -1 :
+            case -1:
                 // do nothing if child invoice has negative amount because it's a credit and it will be use in next invoice
                 return true;
-            case 1 : return false;
-            case 0 :
+            case 1:
+                return false;
+            case 0:
                 // only ignore if amount == 0 and any item is not FIXED or RECURRING
                 for (InvoiceItem item : childInvoice.getInvoiceItems()) {
-                    if (item.getInvoiceItemType().equals(InvoiceItemType.FIXED) || item.getInvoiceItemType().equals(InvoiceItemType.RECURRING)) return false;
+                    if (item.getInvoiceItemType().equals(InvoiceItemType.FIXED) || item.getInvoiceItemType().equals(InvoiceItemType.RECURRING)) {
+                        return false;
+                    }
                 }
         }
 
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModule.java b/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModule.java
index bc4ddeb..5a8fdd3 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModule.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModule.java
@@ -25,14 +25,12 @@ import org.killbill.billing.mock.glue.MockTenantModule;
 import org.killbill.billing.platform.api.KillbillConfigSource;
 import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
 import org.killbill.billing.usage.glue.UsageModule;
-import org.killbill.billing.util.email.EmailModule;
 import org.killbill.billing.util.email.templates.TemplateModule;
 import org.killbill.billing.util.glue.CacheModule;
 import org.killbill.billing.util.glue.CallContextModule;
 import org.killbill.billing.util.glue.ConfigModule;
 import org.killbill.billing.util.glue.CustomFieldModule;
 import org.killbill.billing.util.glue.MemoryGlobalLockerModule;
-import org.killbill.billing.util.glue.TagStoreModule;
 import org.mockito.Mockito;
 
 public class TestInvoiceModule extends DefaultInvoiceModule {
@@ -56,7 +54,6 @@ public class TestInvoiceModule extends DefaultInvoiceModule {
         install(new CacheModule(configSource));
         install(new ConfigModule(configSource));
         install(new TemplateModule(configSource));
-        install(new EmailModule(configSource));
         install(new MockTenantModule(configSource));
 
 
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java
index 5a86cc3..af1ceb2 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java
@@ -37,18 +37,14 @@ import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.catalog.api.PhaseType;
 import org.killbill.billing.catalog.api.Plan;
 import org.killbill.billing.catalog.api.PlanPhase;
-import org.killbill.billing.invoice.InvoiceDispatcher.FutureAccountNotifications;
-import org.killbill.billing.invoice.InvoiceDispatcher.FutureAccountNotifications.SubscriptionNotification;
 import org.killbill.billing.invoice.TestInvoiceHelper.DryRunFutureDateArguments;
 import org.killbill.billing.invoice.api.DryRunArguments;
 import org.killbill.billing.invoice.api.Invoice;
 import org.killbill.billing.invoice.api.InvoiceApiException;
 import org.killbill.billing.invoice.api.InvoiceItem;
 import org.killbill.billing.invoice.api.InvoiceItemType;
-import org.killbill.billing.invoice.api.InvoiceNotifier;
 import org.killbill.billing.invoice.dao.InvoiceItemModelDao;
 import org.killbill.billing.invoice.dao.InvoiceModelDao;
-import org.killbill.billing.invoice.notification.NullInvoiceNotifier;
 import org.killbill.billing.junction.BillingEventSet;
 import org.killbill.billing.subscription.api.SubscriptionBase;
 import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
@@ -64,7 +60,6 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
 
 public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
 
@@ -99,9 +94,8 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
 
         final LocalDate target = internalCallContext.toLocalDate(effectiveDate);
 
-        final InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
         final InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountApi, billingApi, subscriptionApi, invoiceDao,
-                                                                   internalCallContextFactory, invoiceNotifier, invoicePluginDispatcher, locker, busService.getBus(),
+                                                                   internalCallContextFactory, invoicePluginDispatcher, locker, busService.getBus(),
                                                                    null, invoiceConfig, clock, parkedAccountsManager);
 
         Invoice invoice = dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, new DryRunFutureDateArguments(), context);
@@ -143,9 +137,8 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
 
         final LocalDate target = internalCallContext.toLocalDate(effectiveDate);
 
-        final InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
         final InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountApi, billingApi, subscriptionApi, invoiceDao,
-                                                                   internalCallContextFactory, invoiceNotifier, invoicePluginDispatcher, locker, busService.getBus(),
+                                                                   internalCallContextFactory, invoicePluginDispatcher, locker, busService.getBus(),
                                                                    null, invoiceConfig, clock, parkedAccountsManager);
 
         // Verify initial tags state for account
@@ -291,9 +284,8 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
                                                       31, BillingMode.IN_ADVANCE, "CHANGE", 3L, SubscriptionBaseTransitionType.CHANGE));
 
         Mockito.when(billingApi.getBillingEventsForAccountAndUpdateAccountBCD(Mockito.<UUID>any(), Mockito.<DryRunArguments>any(), Mockito.<InternalCallContext>any())).thenReturn(events);
-        final InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
         final InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountApi, billingApi, subscriptionApi, invoiceDao,
-                                                                   internalCallContextFactory, invoiceNotifier, invoicePluginDispatcher, locker, busService.getBus(),
+                                                                   internalCallContextFactory, invoicePluginDispatcher, locker, busService.getBus(),
                                                                    null, invoiceConfig, clock, parkedAccountsManager);
 
         final Invoice invoice = dispatcher.processAccountFromNotificationOrBusEvent(account.getId(), new LocalDate("2012-07-30"), null, context);
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
index e1df2df..6cf3f1a 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
@@ -57,7 +57,6 @@ import org.killbill.billing.invoice.api.DryRunType;
 import org.killbill.billing.invoice.api.Invoice;
 import org.killbill.billing.invoice.api.InvoiceApiException;
 import org.killbill.billing.invoice.api.InvoiceItem;
-import org.killbill.billing.invoice.api.InvoiceNotifier;
 import org.killbill.billing.invoice.api.InvoicePayment;
 import org.killbill.billing.invoice.dao.InvoiceDao;
 import org.killbill.billing.invoice.dao.InvoiceItemModelDao;
@@ -68,7 +67,6 @@ import org.killbill.billing.invoice.dao.InvoicePaymentModelDao;
 import org.killbill.billing.invoice.dao.InvoicePaymentSqlDao;
 import org.killbill.billing.invoice.dao.InvoiceSqlDao;
 import org.killbill.billing.invoice.generator.InvoiceGenerator;
-import org.killbill.billing.invoice.notification.NullInvoiceNotifier;
 import org.killbill.billing.junction.BillingEvent;
 import org.killbill.billing.junction.BillingEventSet;
 import org.killbill.billing.junction.BillingInternalApi;
@@ -211,9 +209,8 @@ public class TestInvoiceHelper {
 
         Mockito.when(billingApi.getBillingEventsForAccountAndUpdateAccountBCD(Mockito.<UUID>any(), Mockito.<DryRunArguments>any(), Mockito.<InternalCallContext>any())).thenReturn(events);
 
-        final InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
         final InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountApi, billingApi, subscriptionApi,
-                                                                   invoiceDao, internalCallContextFactory, invoiceNotifier, invoicePluginDispatcher, locker, busService.getBus(),
+                                                                   invoiceDao, internalCallContextFactory, invoicePluginDispatcher, locker, busService.getBus(),
                                                                    null, invoiceConfig, clock, parkedAccountsManager);
 
         Invoice invoice = dispatcher.processAccountFromNotificationOrBusEvent(account.getId(), targetDate, new DryRunFutureDateArguments(), internalCallContext);
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/mappers/ExceptionMapperBase.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/mappers/ExceptionMapperBase.java
index 95a7a37..c4b79cd 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/mappers/ExceptionMapperBase.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/mappers/ExceptionMapperBase.java
@@ -38,7 +38,6 @@ import org.killbill.billing.subscription.api.SubscriptionBillingApiException;
 import org.killbill.billing.subscription.api.timeline.SubscriptionBaseRepairException;
 import org.killbill.billing.util.api.TagApiException;
 import org.killbill.billing.util.api.TagDefinitionApiException;
-import org.killbill.billing.util.email.EmailApiException;
 import org.killbill.billing.util.jackson.ObjectMapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -75,9 +74,6 @@ public abstract class ExceptionMapperBase {
         } else if (cause instanceof CatalogApiException) {
             final CatalogApiExceptionMapper mapper = new CatalogApiExceptionMapper(uriInfo);
             return mapper.toResponse((CatalogApiException) cause);
-        } else if (cause instanceof EmailApiException) {
-            final EmailApiExceptionMapper mapper = new EmailApiExceptionMapper(uriInfo);
-            return mapper.toResponse((EmailApiException) cause);
         } else if (cause instanceof EntitlementApiException) {
             final EntitlementApiExceptionMapper mapper = new EntitlementApiExceptionMapper(uriInfo);
             return mapper.toResponse((EntitlementApiException) cause);
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
index 2e815f3..4592153 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
@@ -73,7 +73,6 @@ import org.killbill.billing.invoice.api.DryRunType;
 import org.killbill.billing.invoice.api.Invoice;
 import org.killbill.billing.invoice.api.InvoiceApiException;
 import org.killbill.billing.invoice.api.InvoiceItem;
-import org.killbill.billing.invoice.api.InvoiceNotifier;
 import org.killbill.billing.invoice.api.InvoicePayment;
 import org.killbill.billing.invoice.api.InvoiceUserApi;
 import org.killbill.billing.jaxrs.json.CustomFieldJson;
@@ -136,7 +135,6 @@ public class InvoiceResource extends JaxRsResourceBase {
     private static final String LOCALE_PARAM_NAME = "locale";
 
     private final InvoiceUserApi invoiceApi;
-    private final InvoiceNotifier invoiceNotifier;
     private final TenantUserApi tenantApi;
     private final Locale defaultLocale;
 
@@ -151,7 +149,6 @@ public class InvoiceResource extends JaxRsResourceBase {
     public InvoiceResource(final AccountUserApi accountUserApi,
                            final InvoiceUserApi invoiceApi,
                            final PaymentApi paymentApi,
-                           final InvoiceNotifier invoiceNotifier,
                            final Clock clock,
                            final JaxrsUriBuilder uriBuilder,
                            final TagUserApi tagUserApi,
@@ -161,7 +158,6 @@ public class InvoiceResource extends JaxRsResourceBase {
                            final Context context) {
         super(uriBuilder, tagUserApi, customFieldUserApi, auditUserApi, accountUserApi, paymentApi, null, clock, context);
         this.invoiceApi = invoiceApi;
-        this.invoiceNotifier = invoiceNotifier;
         this.tenantApi = tenantApi;
         this.defaultLocale = Locale.getDefault();
     }
@@ -341,12 +337,11 @@ public class InvoiceResource extends JaxRsResourceBase {
 
         final Account account = accountUserApi.getAccountById(accountId, callContext);
         final Iterable<InvoiceItem> sanitizedInvoiceItems = validateSanitizeAndTranformInputItems(account.getCurrency(), items);
-        final LocalDate resolvedTargetDate =  toLocalDateDefaultToday(account, targetDate, callContext);
+        final LocalDate resolvedTargetDate = toLocalDateDefaultToday(account, targetDate, callContext);
         final UUID invoiceId = invoiceApi.createMigrationInvoice(accountId, resolvedTargetDate, sanitizedInvoiceItems, callContext);
         return uriBuilder.buildResponse(uriInfo, InvoiceResource.class, "getInvoice", invoiceId, request);
     }
 
-
     @TimedResource
     @POST
     @Path("/" + DRY_RUN)
@@ -663,7 +658,6 @@ public class InvoiceResource extends JaxRsResourceBase {
                              payment.getPurchasedAmount(), "InvoicePaymentJson purchasedAmount needs to be set");
         Preconditions.checkArgument(!externalPayment || payment.getPaymentMethodId() == null, "InvoicePaymentJson should not contain a paymentMethodId when this is an external payment");
 
-
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
 
@@ -681,34 +675,6 @@ public class InvoiceResource extends JaxRsResourceBase {
     }
 
     @TimedResource
-    @POST
-    @Path("/{invoiceId:" + UUID_PATTERN + "}/" + EMAIL_NOTIFICATIONS)
-    @Consumes(APPLICATION_JSON)
-    @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Trigger an email notification for invoice")
-    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice id supplied"),
-                           @ApiResponse(code = 404, message = "Account or invoice not found")})
-    public Response triggerEmailNotificationForInvoice(@PathParam("invoiceId") final String invoiceId,
-                                                       @HeaderParam(HDR_CREATED_BY) final String createdBy,
-                                                       @HeaderParam(HDR_REASON) final String reason,
-                                                       @HeaderParam(HDR_COMMENT) final String comment,
-                                                       @javax.ws.rs.core.Context final HttpServletRequest request) throws InvoiceApiException, AccountApiException {
-        final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
-
-        final Invoice invoice = invoiceApi.getInvoice(UUID.fromString(invoiceId), callContext);
-        if (invoice == null) {
-            throw new InvoiceApiException(ErrorCode.INVOICE_NOT_FOUND, invoiceId);
-        }
-
-        final Account account = accountUserApi.getAccountById(invoice.getAccountId(), callContext);
-
-        // Send the email (synchronous send)
-        invoiceNotifier.notify(account, invoice, callContext);
-
-        return Response.status(Status.OK).build();
-    }
-
-    @TimedResource
     @GET
     @Path("/" + INVOICE_TRANSLATION + "/{locale:" + ANYTHING_PATTERN + "}/")
     @Produces(TEXT_PLAIN)
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueStateApplicator.java b/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueStateApplicator.java
index bdab42c..b880b1d 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueStateApplicator.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueStateApplicator.java
@@ -18,7 +18,6 @@
 
 package org.killbill.billing.overdue.applicator;
 
-import java.io.IOException;
 import java.util.Collection;
 import java.util.LinkedList;
 import java.util.List;
@@ -30,12 +29,10 @@ import org.joda.time.DateTime;
 import org.joda.time.Period;
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.ObjectType;
-import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountInternalApi;
 import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.InternalCallContext;
-import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.BillingActionPolicy;
 import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.entitlement.EntitlementInternalApi;
@@ -63,23 +60,16 @@ import org.killbill.billing.tag.TagInternalApi;
 import org.killbill.billing.util.api.TagApiException;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
-import org.killbill.billing.util.email.DefaultEmailSender;
-import org.killbill.billing.util.email.EmailApiException;
-import org.killbill.billing.util.email.EmailConfig;
-import org.killbill.billing.util.email.EmailSender;
 import org.killbill.billing.util.tag.ControlTagType;
 import org.killbill.billing.util.tag.Tag;
 import org.killbill.bus.api.PersistentBus;
-import org.killbill.clock.Clock;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Predicate;
-import com.google.common.base.Strings;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
 import com.google.inject.Inject;
-import com.samskivert.mustache.MustacheException;
 
 public class OverdueStateApplicator {
 
@@ -91,9 +81,7 @@ public class OverdueStateApplicator {
     private final AccountInternalApi accountApi;
     private final EntitlementApi entitlementApi;
     private final EntitlementInternalApi entitlementInternalApi;
-    private final OverdueEmailGenerator overdueEmailGenerator;
     private final TagInternalApi tagApi;
-    private final EmailSender emailSender;
     private final InternalCallContextFactory internalCallContextFactory;
 
     @Inject
@@ -102,8 +90,6 @@ public class OverdueStateApplicator {
                                   final EntitlementApi entitlementApi,
                                   final EntitlementInternalApi entitlementInternalApi,
                                   @Named(DefaultOverdueModule.OVERDUE_NOTIFIER_CHECK_NAMED) final OverduePoster checkPoster,
-                                  final OverdueEmailGenerator overdueEmailGenerator,
-                                  final EmailConfig config,
                                   final PersistentBus bus,
                                   final TagInternalApi tagApi,
                                   final InternalCallContextFactory internalCallContextFactory) {
@@ -113,60 +99,52 @@ public class OverdueStateApplicator {
         this.entitlementApi = entitlementApi;
         this.entitlementInternalApi = entitlementInternalApi;
         this.checkPoster = checkPoster;
-        this.overdueEmailGenerator = overdueEmailGenerator;
         this.tagApi = tagApi;
         this.internalCallContextFactory = internalCallContextFactory;
-        this.emailSender = new DefaultEmailSender(config);
         this.bus = bus;
     }
 
     public void apply(final DateTime effectiveDate, final OverdueStateSet overdueStateSet, final BillingState billingState,
                       final ImmutableAccountData account, final OverdueState previousOverdueState,
                       final OverdueState nextOverdueState, final InternalCallContext context) throws OverdueException, OverdueApiException {
-        try {
-            if (isAccountTaggedWith_OVERDUE_ENFORCEMENT_OFF(context)) {
-                log.debug("OverdueStateApplicator: apply returns because account (recordId={}) is set with OVERDUE_ENFORCEMENT_OFF", context.getAccountRecordId());
-                return;
-            }
+        if (isAccountTaggedWith_OVERDUE_ENFORCEMENT_OFF(context)) {
+            log.debug("OverdueStateApplicator: apply returns because account (recordId={}) is set with OVERDUE_ENFORCEMENT_OFF", context.getAccountRecordId());
+            return;
+        }
 
-            log.debug("OverdueStateApplicator: time={}, previousState={}, nextState={}, billingState={}", effectiveDate, previousOverdueState, nextOverdueState, billingState);
-
-            final OverdueState firstOverdueState = overdueStateSet.getFirstState();
-            final boolean conditionForNextNotfication = !nextOverdueState.isClearState() ||
-                                                        // We did not reach the first state yet but we have an unpaid invoice
-                                                        (firstOverdueState != null && billingState != null && billingState.getDateOfEarliestUnpaidInvoice() != null);
-
-            if (conditionForNextNotfication) {
-                final Period reevaluationInterval = getReevaluationInterval(overdueStateSet, nextOverdueState);
-                // If there is no configuration in the config, we assume this is because the overdue conditions are not time based and so there is nothing to retry
-                if (reevaluationInterval == null) {
-                    log.debug("OverdueStateApplicator <notificationQ>: missing InitialReevaluationInterval from config, NOT inserting notification for account {}", account.getId());
-                } else {
-                    log.debug("OverdueStateApplicator <notificationQ>: inserting notification for account={}, time={}", account.getId(), effectiveDate.plus(reevaluationInterval));
-                    createFutureNotification(account, effectiveDate.plus(reevaluationInterval), context);
-                }
-            } else if (nextOverdueState.isClearState()) {
-                clearFutureNotification(account, context);
-            }
+        log.debug("OverdueStateApplicator: time={}, previousState={}, nextState={}, billingState={}", effectiveDate, previousOverdueState, nextOverdueState, billingState);
+
+        final OverdueState firstOverdueState = overdueStateSet.getFirstState();
+        final boolean conditionForNextNotfication = !nextOverdueState.isClearState() ||
+                                                    // We did not reach the first state yet but we have an unpaid invoice
+                                                    (firstOverdueState != null && billingState != null && billingState.getDateOfEarliestUnpaidInvoice() != null);
 
-            if (previousOverdueState.getName().equals(nextOverdueState.getName())) {
-                log.debug("OverdueStateApplicator is no-op: previousState={}, nextState={}", previousOverdueState, nextOverdueState);
-                return;
+        if (conditionForNextNotfication) {
+            final Period reevaluationInterval = getReevaluationInterval(overdueStateSet, nextOverdueState);
+            // If there is no configuration in the config, we assume this is because the overdue conditions are not time based and so there is nothing to retry
+            if (reevaluationInterval == null) {
+                log.debug("OverdueStateApplicator <notificationQ>: missing InitialReevaluationInterval from config, NOT inserting notification for account {}", account.getId());
+            } else {
+                log.debug("OverdueStateApplicator <notificationQ>: inserting notification for account={}, time={}", account.getId(), effectiveDate.plus(reevaluationInterval));
+                createFutureNotification(account, effectiveDate.plus(reevaluationInterval), context);
             }
+        } else if (nextOverdueState.isClearState()) {
+            clearFutureNotification(account, context);
+        }
 
-            cancelSubscriptionsIfRequired(effectiveDate, account, nextOverdueState, context);
+        if (previousOverdueState.getName().equals(nextOverdueState.getName())) {
+            log.debug("OverdueStateApplicator is no-op: previousState={}, nextState={}", previousOverdueState, nextOverdueState);
+            return;
+        }
 
-            sendEmailIfRequired(account.getId(), billingState, nextOverdueState, context);
+        cancelSubscriptionsIfRequired(effectiveDate, account, nextOverdueState, context);
 
-            avoid_extra_credit_by_toggling_AUTO_INVOICE_OFF(account, previousOverdueState, nextOverdueState, context);
+        avoid_extra_credit_by_toggling_AUTO_INVOICE_OFF(account, previousOverdueState, nextOverdueState, context);
 
-            // Make sure to store the new state last here: the entitlement DAO will send a BlockingTransitionInternalEvent
-            // on the bus to which invoice will react. We need the latest state (including AUTO_INVOICE_OFF tag for example)
-            // to be present in the database first.
-            storeNewState(effectiveDate, account, nextOverdueState, context);
-        } catch (final AccountApiException e) {
-            throw new OverdueException(e);
-        }
+        // Make sure to store the new state last here: the entitlement DAO will send a BlockingTransitionInternalEvent
+        // on the bus to which invoice will react. We need the latest state (including AUTO_INVOICE_OFF tag for example)
+        // to be present in the database first.
+        storeNewState(effectiveDate, account, nextOverdueState, context);
 
         final OverdueChangeInternalEvent event;
         try {
@@ -354,45 +332,6 @@ public class OverdueStateApplicator {
         result.addAll(allEntitlementsButAddonsForAccountId);
     }
 
-    private void sendEmailIfRequired(final UUID accountId, final BillingState billingState,
-                                     final OverdueState nextOverdueState, final InternalTenantContext context) throws AccountApiException {
-        // Note: we don't want to fail the full refresh call because sending the email failed.
-        // That's the reason why we catch all exceptions here.
-        // The alternative would be to: throw new OverdueApiException(e, ErrorCode.EMAIL_SENDING_FAILED);
-
-        // If sending is not configured, skip
-        if (nextOverdueState.getEmailNotification() == null) {
-            return;
-        }
-
-        final Account account = accountApi.getAccountById(accountId, context);
-        if (Strings.emptyToNull(account.getEmail()) == null) {
-            log.warn("Unable to send overdue notification email for account {} and overdueable {}: no email specified", account.getId(), account.getId());
-            return;
-        }
-
-        final List<String> to = ImmutableList.<String>of(account.getEmail());
-        // TODO - should we look at the account CC: list?
-        final List<String> cc = ImmutableList.<String>of();
-        final String subject = nextOverdueState.getEmailNotification().getSubject();
-
-        try {
-            // Generate and send the email
-            final String emailBody = overdueEmailGenerator.generateEmail(account, billingState, account, nextOverdueState);
-            if (nextOverdueState.getEmailNotification().isHTML()) {
-                emailSender.sendHTMLEmail(to, cc, subject, emailBody);
-            } else {
-                emailSender.sendPlainTextEmail(to, cc, subject, emailBody);
-            }
-        } catch (final IOException e) {
-            log.warn("Unable to generate or send overdue notification email for accountId='{}'", account.getId(), e);
-        } catch (final EmailApiException e) {
-            log.warn("Unable to send overdue notification email for accountId='{}'", account.getId(), e);
-        } catch (final MustacheException e) {
-            log.warn("Unable to generate overdue notification email for accountId='{}'", account.getId(), e);
-        }
-    }
-
     //
     // Uses callcontext information to retrieve account matching the Overduable object and check whether we should do any overdue processing
     //
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/config/DefaultEmailNotification.java b/overdue/src/main/java/org/killbill/billing/overdue/config/DefaultEmailNotification.java
index ea314cb..c7167b7 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/config/DefaultEmailNotification.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/config/DefaultEmailNotification.java
@@ -22,8 +22,9 @@ import javax.xml.bind.annotation.XmlElement;
 
 import org.killbill.billing.overdue.api.EmailNotification;
 
+@Deprecated // Not used, just kept for config compatibility
 @XmlAccessorType(XmlAccessType.NONE)
-public class DefaultEmailNotification implements EmailNotification {
+public class DefaultEmailNotification {
 
     @XmlElement(required = true, name = "subject")
     private String subject;
@@ -33,19 +34,4 @@ public class DefaultEmailNotification implements EmailNotification {
 
     @XmlElement(required = false, name = "isHTML")
     private Boolean isHTML = false;
-
-    @Override
-    public String getSubject() {
-        return subject;
-    }
-
-    @Override
-    public String getTemplateName() {
-        return templateName;
-    }
-
-    @Override
-    public Boolean isHTML() {
-        return isHTML;
-    }
 }
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/config/DefaultOverdueState.java b/overdue/src/main/java/org/killbill/billing/overdue/config/DefaultOverdueState.java
index 6c57ffd..233a0ca 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/config/DefaultOverdueState.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/config/DefaultOverdueState.java
@@ -18,8 +18,11 @@
 
 package org.killbill.billing.overdue.config;
 
+import java.util.List;
+
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAnyElement;
 import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlID;
@@ -68,6 +71,7 @@ public class DefaultOverdueState extends ValidatingConfig<DefaultOverdueConfig> 
     @XmlElement(required = false, name = "autoReevaluationInterval")
     private DefaultDuration autoReevaluationInterval;
 
+    @Deprecated // Not used, just kept for config compatibility
     @XmlElement(required = false, name = "enterStateEmailNotification")
     private DefaultEmailNotification enterStateEmailNotification;
 
@@ -174,10 +178,6 @@ public class DefaultOverdueState extends ValidatingConfig<DefaultOverdueConfig> 
         return errors;
     }
 
-    @Override
-    public EmailNotification getEmailNotification() {
-        return enterStateEmailNotification;
-    }
 
     @Override
     public String toString() {
@@ -190,7 +190,6 @@ public class DefaultOverdueState extends ValidatingConfig<DefaultOverdueConfig> 
         sb.append(", subscriptionCancellationPolicy=").append(subscriptionCancellationPolicy);
         sb.append(", isClearState=").append(isClearState);
         sb.append(", autoReevaluationInterval=").append(autoReevaluationInterval);
-        sb.append(", enterStateEmailNotification=").append(enterStateEmailNotification);
         sb.append('}');
         return sb.toString();
     }
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/config/DefaultOverdueStatesAccount.java b/overdue/src/main/java/org/killbill/billing/overdue/config/DefaultOverdueStatesAccount.java
index 004fd2d..c384444 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/config/DefaultOverdueStatesAccount.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/config/DefaultOverdueStatesAccount.java
@@ -16,6 +16,9 @@
 
 package org.killbill.billing.overdue.config;
 
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAnyElement;
 import javax.xml.bind.annotation.XmlElement;
 
 import org.joda.time.Period;
@@ -32,6 +35,7 @@ public class DefaultOverdueStatesAccount extends DefaultOverdueStateSet implemen
     @XmlElement(required = true, name = "state")
     private DefaultOverdueState[] accountOverdueStates = new DefaultOverdueState[0];
 
+
     @Override
     public DefaultOverdueState[] getStates() {
         return accountOverdueStates;
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/glue/DefaultOverdueModule.java b/overdue/src/main/java/org/killbill/billing/overdue/glue/DefaultOverdueModule.java
index 930c774..9a00618 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/glue/DefaultOverdueModule.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/glue/DefaultOverdueModule.java
@@ -23,9 +23,6 @@ import org.killbill.billing.overdue.OverdueProperties;
 import org.killbill.billing.overdue.OverdueService;
 import org.killbill.billing.overdue.api.DefaultOverdueApi;
 import org.killbill.billing.overdue.api.OverdueApi;
-import org.killbill.billing.overdue.applicator.OverdueEmailGenerator;
-import org.killbill.billing.overdue.applicator.formatters.DefaultOverdueEmailFormatterFactory;
-import org.killbill.billing.overdue.applicator.formatters.OverdueEmailFormatterFactory;
 import org.killbill.billing.overdue.caching.EhCacheOverdueConfigCache;
 import org.killbill.billing.overdue.caching.OverdueCacheInvalidationCallback;
 import org.killbill.billing.overdue.caching.OverdueConfigCache;
@@ -64,7 +61,6 @@ public class DefaultOverdueModule extends KillBillModule implements OverdueModul
         // internal bindings
         installOverdueService();
         installOverdueWrapperFactory();
-        installOverdueEmail();
 
         final OverdueProperties config = new ConfigurationObjectFactory(skifeConfigSource).build(OverdueProperties.class);
         bind(OverdueProperties.class).toInstance(config);
@@ -86,11 +82,6 @@ public class DefaultOverdueModule extends KillBillModule implements OverdueModul
         bind(OverdueWrapperFactory.class).asEagerSingleton();
     }
 
-    protected void installOverdueEmail() {
-        bind(OverdueEmailFormatterFactory.class).to(DefaultOverdueEmailFormatterFactory.class).asEagerSingleton();
-        bind(OverdueEmailGenerator.class).asEagerSingleton();
-    }
-
     @Override
     public void installOverdueUserApi() {
         bind(OverdueApi.class).to(DefaultOverdueApi.class).asEagerSingleton();
diff --git a/overdue/src/test/java/org/killbill/billing/overdue/config/TestOverdueConfig.java b/overdue/src/test/java/org/killbill/billing/overdue/config/TestOverdueConfig.java
index d4326db..f0209b9 100644
--- a/overdue/src/test/java/org/killbill/billing/overdue/config/TestOverdueConfig.java
+++ b/overdue/src/test/java/org/killbill/billing/overdue/config/TestOverdueConfig.java
@@ -70,16 +70,9 @@ public class TestOverdueConfig extends OverdueTestSuiteNoDB {
         final DefaultOverdueConfig c = XMLLoader.getObjectFromStreamNoValidation(is, DefaultOverdueConfig.class);
         Assert.assertEquals(c.getOverdueStatesAccount().size(), 2);
 
-        Assert.assertNull(c.getOverdueStatesAccount().getStates()[1].getEmailNotification());
-
         Assert.assertNotNull(c.getOverdueStatesAccount().getInitialReevaluationInterval());
         Assert.assertEquals(c.getOverdueStatesAccount().getInitialReevaluationInterval().getDays(), 1);
 
-        final EmailNotification secondNotification = c.getOverdueStatesAccount().getStates()[0].getEmailNotification();
-        Assert.assertEquals(secondNotification.getSubject(), "ToTo");
-        Assert.assertEquals(secondNotification.getTemplateName(), "Titi");
-        Assert.assertFalse(secondNotification.isHTML());
-
         Assert.assertEquals(c.getOverdueStatesAccount().getFirstState().getName(), "OD1");
     }
 }
diff --git a/overdue/src/test/java/org/killbill/billing/overdue/glue/TestOverdueModule.java b/overdue/src/test/java/org/killbill/billing/overdue/glue/TestOverdueModule.java
index 8d603af..21943cd 100644
--- a/overdue/src/test/java/org/killbill/billing/overdue/glue/TestOverdueModule.java
+++ b/overdue/src/test/java/org/killbill/billing/overdue/glue/TestOverdueModule.java
@@ -40,7 +40,6 @@ import org.killbill.billing.overdue.caching.OverdueConfigCache;
 import org.killbill.billing.overdue.wrapper.OverdueWrapper;
 import org.killbill.billing.platform.api.KillbillConfigSource;
 import org.killbill.billing.tenant.api.TenantInternalApi.CacheInvalidationCallback;
-import org.killbill.billing.util.email.EmailModule;
 import org.killbill.billing.util.email.templates.TemplateModule;
 import org.killbill.billing.util.glue.AuditModule;
 import org.killbill.billing.util.glue.CacheModule;
@@ -66,7 +65,6 @@ public class TestOverdueModule extends DefaultOverdueModule {
         install(new ConfigModule(configSource));
         install(new CallContextModule(configSource));
         install(new CustomFieldModule(configSource));
-        install(new EmailModule(configSource));
         install(new MockAccountModule(configSource));
         install(new MockEntitlementModule(configSource, new ApplicatorBlockingApi()));
         install(new MockInvoiceModule(configSource));
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillServerModule.java b/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillServerModule.java
index 5c74bcb..92668d3 100644
--- a/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillServerModule.java
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillServerModule.java
@@ -31,7 +31,6 @@ import org.killbill.billing.jaxrs.resources.AccountResource;
 import org.killbill.billing.jaxrs.resources.AdminResource;
 import org.killbill.billing.jaxrs.resources.BundleResource;
 import org.killbill.billing.jaxrs.resources.CatalogResource;
-import org.killbill.billing.jaxrs.resources.ComboPaymentResource;
 import org.killbill.billing.jaxrs.resources.CreditResource;
 import org.killbill.billing.jaxrs.resources.CustomFieldResource;
 import org.killbill.billing.jaxrs.resources.ExportResource;
@@ -68,7 +67,6 @@ import org.killbill.billing.subscription.glue.DefaultSubscriptionModule;
 import org.killbill.billing.tenant.glue.DefaultTenantModule;
 import org.killbill.billing.usage.glue.UsageModule;
 import org.killbill.billing.util.config.definition.NotificationConfig;
-import org.killbill.billing.util.email.EmailModule;
 import org.killbill.billing.util.email.templates.TemplateModule;
 import org.killbill.billing.util.glue.AuditModule;
 import org.killbill.billing.util.glue.BroadcastModule;
@@ -170,7 +168,6 @@ public class KillbillServerModule extends KillbillPlatformModule {
         install(new DefaultJunctionModule(configSource));
         install(new DefaultOverdueModule(configSource));
         install(new DefaultSubscriptionModule(configSource));
-        install(new EmailModule(configSource));
         install(new ExportModule(configSource));
         install(new GlobalLockerModule(configSource));
         install(new KillBillShiroAopModule());
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestJaxrsBase.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestJaxrsBase.java
index 66007ef..0488304 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestJaxrsBase.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestJaxrsBase.java
@@ -37,13 +37,10 @@ import org.killbill.billing.GuicyKillbillTestWithEmbeddedDBModule;
 import org.killbill.billing.api.TestApiListener;
 import org.killbill.billing.client.KillBillClient;
 import org.killbill.billing.client.KillBillHttpClient;
-import org.killbill.billing.client.RequestOptions;
 import org.killbill.billing.client.model.Payment;
 import org.killbill.billing.client.model.PaymentTransaction;
 import org.killbill.billing.client.model.Tenant;
-import org.killbill.billing.invoice.api.InvoiceNotifier;
 import org.killbill.billing.invoice.glue.DefaultInvoiceModule;
-import org.killbill.billing.invoice.notification.NullInvoiceNotifier;
 import org.killbill.billing.jetty.HttpServer;
 import org.killbill.billing.jetty.HttpServerConfig;
 import org.killbill.billing.lifecycle.glue.BusModule;
@@ -145,10 +142,6 @@ public class TestJaxrsBase extends KillbillClient {
             super(configSource);
         }
 
-        @Override
-        protected void installInvoiceNotifier() {
-            bind(InvoiceNotifier.class).to(NullInvoiceNotifier.class).asEagerSingleton();
-        }
     }
 
     private final class PaymentMockModule extends PaymentModule {
diff --git a/profiles/killpay/src/main/java/org/killbill/billing/server/modules/KillpayServerModule.java b/profiles/killpay/src/main/java/org/killbill/billing/server/modules/KillpayServerModule.java
index 0f6f52d..b4b8f6d 100644
--- a/profiles/killpay/src/main/java/org/killbill/billing/server/modules/KillpayServerModule.java
+++ b/profiles/killpay/src/main/java/org/killbill/billing/server/modules/KillpayServerModule.java
@@ -52,7 +52,6 @@ import org.killbill.billing.server.config.KillbillServerConfig;
 import org.killbill.billing.subscription.glue.DefaultSubscriptionModule;
 import org.killbill.billing.tenant.glue.DefaultTenantModule;
 import org.killbill.billing.usage.glue.UsageModule;
-import org.killbill.billing.util.email.EmailModule;
 import org.killbill.billing.util.email.templates.TemplateModule;
 import org.killbill.billing.util.glue.AuditModule;
 import org.killbill.billing.util.glue.BroadcastModule;
@@ -112,7 +111,6 @@ public class KillpayServerModule extends KillbillServerModule {
         install(new DefaultJaxrsModule(configSource));
         // TODO Dependencies for AccountResource
         install(new DefaultOverdueModule(configSource));
-        install(new EmailModule(configSource));
     }
 
     @Override