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

com.google.appengine.api.mail.dev.LocalMailService Maven / Gradle / Ivy

Go to download

SDK for dev_appserver (local development) with some of the dependencies shaded (repackaged)

There is a newer version: 2.0.31
Show newest version
/*
 * Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.appengine.api.mail.dev;

import com.google.appengine.api.mail.MailService;
import com.google.appengine.api.mail.MailServicePb;
import com.google.appengine.api.mail.MailServicePb.MailAttachment;
import com.google.appengine.api.mail.MailServicePb.MailServiceError;
import com.google.appengine.api.mail.MailStubServicePb;
import com.google.appengine.tools.development.AbstractLocalRpcService;
import com.google.appengine.tools.development.LocalRpcService;
import com.google.appengine.tools.development.LocalServiceContext;
import com.google.apphosting.api.ApiProxy;
import com.google.apphosting.base.protos.api.ApiBasePb;
import com.google.auto.service.AutoService;
import com.google.appengine.repackaged.com.google.common.base.Ascii;
import com.google.appengine.repackaged.com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Stub implementation of the Google App Engine mail api.
 * This implementation logs messages using a {@link Logger} associated with
 * this class and keeps messages that were sent in memory.  If you want to
 * access the list of sent messages you can get ahold of the registered
 * LocalMailService instance as follows:
 *
 * 
*
 * ApiProxyLocal proxy = (ApiProxyLocal) ApiProxy.getDelegate();
 * LocalMailService mailService =
 *     (LocalMailService) proxy.getService(LocalMailService.PACKAGE);
 * 
*
* * You can then access the list via {@link #getSentMessages()} and clear the * list via {@link #clearSentMessages()}. * * By default, messages are logged at {@link Level#INFO} and the body of the * message is excluded. The log level and whether or not the body of the * message is logged can be configured. See {@link #LOG_MAIL_BODY_PROPERTY} * and {@link #LOG_MAIL_LEVEL_PROPERTY} for more information. * */ @AutoService(LocalRpcService.class) public final class LocalMailService extends AbstractLocalRpcService { // TODO: Provide an implementation that delegates to javax.mail so that // we can actually send mail in the local runtime. /** The package name for this service. */ public static final String PACKAGE = "mail"; /** * Init property that determines whether or not we log the body of the email. * Value must be a string representation of either {@link Boolean#TRUE} or * {@link Boolean#FALSE}. */ public static final String LOG_MAIL_BODY_PROPERTY = "mail.log_mail_body"; static final boolean DEFAULT_LOG_MAIL_BODY = false; /** * Init property that specifies the {@link Level} at which we log mail * messages. Value must be a string representation of a {@link Level} * (calling {@link Level#parse(String)} with the value as the arg should * return a valid instance). */ public static final String LOG_MAIL_LEVEL_PROPERTY = "mail.log_mail_level"; static final Level DEFAULT_LOG_MAIL_LEVEL = Level.INFO; // Visible for testing boolean logMailBody = DEFAULT_LOG_MAIL_BODY; // Visible for testing Level logMailLevel = DEFAULT_LOG_MAIL_LEVEL; // Visible for testing Logger logger = Logger.getLogger(getClass().getName()); // Visible for testing static final ImmutableSet DENYLIST = ImmutableSet.of( // N.B. Keep synchronized with //depot/google3/apphosting/api/email_message_builder.cc "ade", "adp", "bat", "chm", "cmd", "com", "cpl", "exe", "hta", "ins", "isp", "jse", "lib", "mde", "msc", "msp", "mst", "pif", "scr", "sct", "shb", "sys", "vb", "vbe", "vbs", "vxd", "wsc", "wsf", "wsh"); // N.B. denylisting of ".zip" and ".gzip" are optional in email_message_builder /** All messages that have been sent. */ private final List sentMessages = Collections.synchronizedList(new ArrayList()); @Override public String getPackage() { return PACKAGE; } @Override public void init(LocalServiceContext context, Map properties) { String logMailBodyStr = properties.get(LOG_MAIL_BODY_PROPERTY); if (logMailBodyStr != null) { logMailBody = Boolean.parseBoolean(logMailBodyStr); } else { logMailBody = DEFAULT_LOG_MAIL_BODY; } String logLevelStr = properties.get(LOG_MAIL_LEVEL_PROPERTY); if (logLevelStr != null) { logMailLevel = Level.parse(logLevelStr); } else { logMailLevel = DEFAULT_LOG_MAIL_LEVEL; } } @Override public void start() { } @Override public void stop() { clearSentMessages(); } public ApiBasePb.VoidProto send(Status status, MailServicePb.MailMessage msg) { logMailMessage("send", msg); checkAttachments(msg); sentMessages.add(msg); return ApiBasePb.VoidProto.getDefaultInstance(); } public ApiBasePb.VoidProto sendToAdmins(Status status, MailServicePb.MailMessage msg) { logMailMessage("sendToAdmins", msg); checkAttachments(msg); sentMessages.add(msg); return ApiBasePb.VoidProto.getDefaultInstance(); } private void checkAttachments(MailServicePb.MailMessage msg) { for (MailAttachment attachment : msg.getAttachmentList()) { checkAttachmentFileName(attachment.getFileName()); } } private void checkAttachmentFileName(String fileName) { final String invalidTypeMsg = "Invalid attachment type"; fileName = Ascii.toLowerCase(fileName).trim(); if (fileName.startsWith(".")) { // throw new IllegalArgumentException(invalidAttachmentTypeMsg); throw new ApiProxy.ApplicationException( MailServiceError.ErrorCode.INVALID_ATTACHMENT_TYPE.getNumber(), invalidTypeMsg); } final int extensionStart = fileName.lastIndexOf('.'); if (extensionStart == -1) { throw new ApiProxy.ApplicationException( MailServiceError.ErrorCode.INVALID_ATTACHMENT_TYPE.getNumber(), invalidTypeMsg); } String extension = fileName.substring(extensionStart + 1); if (DENYLIST.contains(extension)) { throw new ApiProxy.ApplicationException( MailServiceError.ErrorCode.INVALID_ATTACHMENT_TYPE.getNumber(), invalidTypeMsg); } } private void log(String logMsg) { logger.log(logMailLevel, logMsg); } // Visible for testing void logMailMessage(String method, MailServicePb.MailMessage msg) { log(String.format("%s.%s", MailService.class.getSimpleName(), method)); log(String.format(" From: %s", msg.getSender())); for (String to : msg.getToList()) { log(String.format(" To: %s", to)); } for (String cc : msg.getCcList()) { log(String.format(" Cc: %s", cc)); } for (String bcc : msg.getBccList()) { log(String.format(" Bcc: %s", bcc)); } if (msg.hasReplyTo()) { log(String.format(" Reply-to: %s", msg.getReplyTo())); } log(String.format(" Subject: %s", msg.getSubject())); if (msg.hasTextBody()) { log(" Body:"); log(" Content-type: text/plain"); log(String.format(" Data length: %d", msg.getTextBody().length())); if (logMailBody) { log(String.format("-----\n%s\n-----", msg.getTextBody())); } } if (msg.hasAmpHtmlBody()) { log(" Body:"); log(" Content-type: text/x-amp-html"); log(String.format(" Data length: %d", msg.getAmpHtmlBody().length())); if (logMailBody) { log(String.format("-----\n%s\n-----", msg.getAmpHtmlBody())); } } if (msg.hasHtmlBody()) { log(" Body:"); log(" Content-type: text/html"); log(String.format(" Data length: %d", msg.getHtmlBody().length())); if (logMailBody) { log(String.format("-----\n%s\n-----", msg.getHtmlBody())); } } for (MailServicePb.MailAttachment attachment : msg.getAttachmentList()) { log(" Attachment:"); log(String.format(" File name: %s", attachment.getFileName())); log(String.format(" Data length: %d", attachment.getData().size())); } } /** * @return A list of all messages that have been sent. */ public List getSentMessages() { return getSentMessagesInternal(); } private List getSentMessagesInternal() { return new ArrayList<>(sentMessages); } /** * Clear the list of sent messages. */ public void clearSentMessages() { clearSentMessagesInternal(); } private void clearSentMessagesInternal() { sentMessages.clear(); } MailStubServicePb.GetLogMailBodyResponse getLogMailBody() { return MailStubServicePb.GetLogMailBodyResponse.newBuilder() .setLogMailBody(logMailBody) .build(); } Level getLogMailLevel() { return logMailLevel; } @Override public Integer getMaxApiRequestSize() { // Keep this in sync with MAX_REQUEST_SIZE in . return 32 << 20; // 32 MB } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy