Code Monkey home page Code Monkey logo

createsend-java's Introduction

createsend-java Build Status

A Java library which implements the complete functionality of the Campaign Monitor API.

Installation

Jar files are distributed to Sonatype and Maven Central. Development snapshots are available from the Sonatype snapshots repository, and production releases are available from either the Sonatype releases repository or the Maven Central repository.

Authenticating

The Campaign Monitor API supports authentication using either OAuth or an API key.

Using OAuth

This library helps you authenticate using OAuth, as described in the Campaign Monitor API documentation. You may also wish to reference this Java example application. The authentication process is described below.

The first thing your application should do is redirect your user to the Campaign Monitor authorization URL where they will have the opportunity to approve your application to access their Campaign Monitor account. You can get this authorization URL by using com.createsend.General.getAuthorizeUrl(), like so:

String authorizeUrl = com.createsend.General.getAuthorizeUrl(
    32132,                 // The Client ID for your application
    "http://example.com/", // Redirect URI for your application
    "ViewReports",         // The permission level your application requires
    "some state data"      // Optional state data to be included
);
// Redirect your users to authorizeUrl.

If your user approves your application, they will then be redirected to the redirect URI you specified, which will include a code parameter, and optionally a state parameter in the query string. Your application should implement a handler which can exchange the code passed to it for an access token, using com.createsend.General.exchangeToken() like so:

com.createsend.models.OAuthTokenDetails tokenDetails = com.createsend.General.exchangeToken(
    32132,                 // The Client ID for your application
    "982u39823r928398",    // The Client Secret for your application
    "http://example.com/", // Redirect URI for your application
    "8dw9uq98wu98d"        // The unique code for your user found in the query string
);
// Save your access token, 'expires in' value, and refresh token (in tokenDetails).

At this point you have an access token and refresh token for your user which you should store somewhere convenient so that your application can look up these values when your user wants to make future Campaign Monitor API calls.

Once you have an access token and refresh token for your user, you can authenticate and make further API calls like so:

import com.createsend.General;
import com.createsend.models.clients.ClientBasics;
import com.createsend.util.OAuthAuthenticationDetails;
import com.createsend.util.exceptions.CreateSendException;

public class Tester {
    public static void main(String[] args) throws CreateSendException {
        OAuthAuthenticationDetails auth = new OAuthAuthenticationDetails(
            "your access token", "your refresh token");
        General general = new General(auth);
        ClientBasics[] clients = general.getClients();
    }
}

All OAuth tokens have an expiry time, and can be renewed with a corresponding refresh token. If your access token expires when attempting to make an API call, a com.createsend.util.exceptions.ExpiredOAuthTokenException will be thrown, so your code should handle this. Here's an example of how you could do this:

import com.createsend.General;
import com.createsend.models.clients.ClientBasics;
import com.createsend.util.OAuthAuthenticationDetails;
import com.createsend.util.exceptions.CreateSendException;
import com.createsend.util.exceptions.ExpiredOAuthTokenException;

public class Tester {
    public static void main(String[] args) throws CreateSendException {
        OAuthAuthenticationDetails auth = new OAuthAuthenticationDetails(
            "your access token", "your refresh token");

        General general = new General(auth);
        ClientBasics[] clients;

        try {
            clients = general.getClients();
        } catch (ExpiredOAuthTokenException ex) {
            OAuthTokenDetails newTokenDetails = general.refreshToken();
            // Save your updated access token, 'expires in' value, and refresh token
            clients = general.getClients(); // Make the call again
        }
    }
}

Using an API key

import com.createsend.General;
import com.createsend.models.clients.ClientBasics;
import com.createsend.util.ApiKeyAuthenticationDetails;
import com.createsend.util.exceptions.CreateSendException;

public class Tester {
    public static void main(String[] args) throws CreateSendException {
        ApiKeyAuthenticationDetails auth = new ApiKeyAuthenticationDetails(
            "your api key");
        General general = new General(auth);
        ClientBasics[] clients = general.getClients();
    }
}

Basic usage

This example of listing all your clients and their campaigns demonstrates basic usage of the library and the data returned from the API:

import com.createsend.Clients;
import com.createsend.General;
import com.createsend.models.campaigns.DraftCampaign;
import com.createsend.models.clients.ClientBasics;
import com.createsend.util.OAuthAuthenticationDetails;
import com.createsend.util.exceptions.CreateSendException;

public class Tester {
    public static void main(String[] args) throws CreateSendException {
        OAuthAuthenticationDetails auth = new OAuthAuthenticationDetails(
            "your access token", "your refresh token");
        General general = new General(auth);
        General general = new General(auth);
        ClientBasics[] clients = general.getClients();

        for (ClientBasics cl : clients) {
            System.out.printf("Client: %s\n", cl.Name);
            Clients cls = new Clients(auth, cl.ClientID);
            System.out.printf("- Campaigns:\n");
            for (DraftCampaign cm : cls.draftCampaigns()) {
                System.out.printf("  - %s\n", cm.Subject);
            }
        }
    }
}

See the samples directory for more example code.

Documentation

Full javadoc for this library is available here.

Developing

Build using Gradle:

Run the following command from the root directory of the repository:

gradle -i

Developing with Eclipse:

Gradle can be used to create the .classpath and .project files to import the project into Eclipse. Run the following command from the root directory of the repository:

gradle eclipse

Developing with IDEA

Gradle can be used to create an IDEA project and module files. Run the following command from the root directory of the repository:

gradle idea

Contributing

Please check the guidelines for contributing to this repository.

Releasing

Please check the instructions for releasing this library.

createsend-java's People

Contributors

27red avatar aymandf avatar cmtiml avatar dependabot[bot] avatar geoffcm avatar henrys-cm avatar itgoeslikethis avatar jdennes avatar kalebscholes avatar kareanyi avatar markstaples avatar mlangsworth avatar niawahyuni avatar nufyoot avatar paulduran avatar richardbremner avatar tobio avatar yahyaz avatar zhartmann avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

createsend-java's Issues

NullPointerException raised when attempting to create a campaign when API key is not set.

The following code:

Campaigns campaigns = new Campaigns();
CampaignForCreation c = new CampaignForCreation();
c.Name = "Example";
c.Subject = "Example";
c.FromName = "Example";
c.FromEmail = "[email protected]";
c.ReplyTo = "[email protected]";
c.HtmlUrl = URI.create("http://example.com/content.html");
c.ListIDs = new String[] { "listid" };
c.SegmentIDs = new String[] { "" };
String id = campaigns.create("clientid", c);
System.out.printf("Campaign created with ID: %s", id);

Results in:

Exception in thread "main" java.lang.NullPointerException
    at com.createsend.util.JerseyClientImpl.handleErrorResponse(JerseyClientImpl.java:363)
    at com.createsend.util.JerseyClientImpl.post(JerseyClientImpl.java:207)
    at com.createsend.util.JerseyClientImpl.post(JerseyClientImpl.java:195)
    at com.createsend.Campaigns.create(Campaigns.java:106)
    at Tester.main(Tester.java:24)

What should actually happen is this:

Exception in thread "main" com.createsend.util.exceptions.UnauthorisedException: The CreateSend API responded with the following authentication error 50: Must supply a valid HTTP Basic Authorization header
    at com.createsend.util.JerseyClientImpl.handleErrorResponse(JerseyClientImpl.java:363)
    at com.createsend.util.JerseyClientImpl.get(JerseyClientImpl.java:148)
    at com.createsend.util.JerseyClientImpl.get(JerseyClientImpl.java:133)
    at com.createsend.util.JerseyClientImpl.get(JerseyClientImpl.java:107)
    at com.createsend.General.getClients(General.java:88)
    at Tester.main(Tester.java:31)

Don't use static Configuration

When integrating the library into our project I had a few issues with the Configuration class.

The first problem is, that it uses the SystemClassloader to get its own properties file.
Might work in some cases, in our case it didn't.
I ended up creating my own jersey client without the static Configuration to get it running. Using static classes is a bad idea in most cases as it makes the whole thing untestable and error-prone.

Javadoc errors when running under JDK 1.8

Java 8 introduces doclint for Javadoc comments, much of the commentary in this library is incompatible with the linting rules.

e.g

MavenReportException: Error while creating archive:Exit code: 1 - /Users/tobio/Documents/Projects/createsend-java/target/checkout/src/com/createsend/Administrators.java:28: error: bad use of '>'
[INFO]      * @throws CreateSendException Thrown when the API responds with HTTP Status >= 400

API 5.1.3 fails since yesterday: (HTTP Status: Not Acceptable)

Without changing anything on our side, we cannot send out transactional email anymore since yesterday at roughly noon (CET):

Caused by: com.createsend.util.exceptions.CreateSendHttpException: The API call failed due to an unexpected HTTP error: Not Acceptable
    at com.createsend.util.JerseyClientImpl.handleUnknownError(JerseyClientImpl.java:431)
    at com.createsend.util.JerseyClientImpl.handleErrorResponse(JerseyClientImpl.java:422)
    at com.createsend.util.JerseyClientImpl.post(JerseyClientImpl.java:271)
    at com.createsend.util.JerseyClientImpl.post(JerseyClientImpl.java:243)
    at com.createsend.util.JerseyClientImpl.post(JerseyClientImpl.java:209)
    at com.createsend.SmartEmail.send(SmartEmail.java:118)

The error message is not helpful at all. However, I noticed that everything works (locally) when I update to the most recent API (6.0.2).

Was the old API (5.1.3) discontinued?

invalid mapper configuration in JsonProvider in version 3.1.1

locateMapper(type, mediaType) return defaultMapper instead of your configured mapper.
Call setMapper(configuredMapper) for example to fix this problem.

try:
new Subscribers(auth, mailingList).details("existing email")
for existing user with filled date. Then

com.sun.jersey.api.client.ClientHandlerException: org.codehaus.jackson.map.JsonMappingException: Can not construct instance of java.util.Date from String value '2013-05-31 11:25:00': not a valid representation (error: Can not parse date "2013-05-31 11:25:00": not compatible with any of standard forms ("yyyy-MM-dd'T'HH:mm:ss.SSSZ", "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "EEE, dd MMM yyyy HH:mm:ss zzz", "yyyy-MM-dd"))
at [Source: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@d20346; line: 1, column: 58](through reference chain: com.createsend.models.subscribers.Subscriber["Date"])

is thrown because your configured mapper not used.

Issue reading configuration file

Hi,

I'm trying to use this library inside a Spring Boot application.

Since Spring Boot packages the application resources in a certain way, it reads them differently (see https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/io/ClassPathResource.html). In contrast, com.createsend.util.Configuration uses java.lang.ClassLoader to load its config file and hence doesn't work in a bundled Spring Boot app.

Ideally, the Configuration object should allow setting individual properties via the constructor. Whether these properties come from file or env vars or somewhere else, should be left to the client.

What do you guys think?

Please document the database data types

I have noticed that for a Subscriber the name needs to be a VARCHAR of length < 260. But this library suggests it is a STRING/TEXT. I get a The API call failed due to an unexpected HTTP error: Internal Server Error when I use a very long random name whereas a shorter name works.

Data type Issue of sending Smart Mail of Transactional

Hi guys,

I am using this Java SDK to send out a transactional smart email.
Maven Version is 6.0.0

It works fine for a simple case, but I have an issue when I want to use Liquid in my email template.
The data field of SmartEmailRequest is just Map<String, String>, in that case, I can pass neither List nor Map object to the data field.

I did fix that by creating a custom version of SmartEmail and SmartEmailRequest. using Map<String, Object>

But if the future version can fix that, it would be highly appreciated!

Thanks.

Add IDEA support to gradle

Adding the following to the plugins section will add the ability to generate idea project & module files with a "gradle idea" from the project directory:
apply plugin: 'idea'

Illegal reflective access by com.createsend.util.ErrorDeserialiser

We see following warning using createsend-java 7 on Java 11:

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.createsend.util.ErrorDeserialiser (jar:file:/app.jar!/BOOT-INF/lib/createsend-java-7.0.0.jar!/) to field sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.actualTypeArguments
WARNING: Please consider reporting this to the maintainers of com.createsend.util.ErrorDeserialiser
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release 

The API call failed due to an unexpected HTTP error: Found

Hi I am trying to execute your sample but it is giving error "The API call failed due to an unexpected HTTP error: Found"

ApiKeyAuthenticationDetails auth = new ApiKeyAuthenticationDetails("API Key");
General general = new General(auth);
ClientBasics[] clients = general.getClients();
System.out.println(clients.toString());

I tried to debug app and found that general.getClients() is throwing error while getting resource.get(klass) in JerseyClientImpl class -> get() implementation.
Please help to resolve this issue.

How to access error description?

The following code sometimes fails for batch uploads. How do I access the error response to display the details of the error?

com.createsend.util.exceptions.BadRequestException: The CreateSend API responded with the following client error 210: Subscriber Import had some failures. Check resultData for more details
        at com.createsend.util.JerseyClientImpl.handleAPIErrorResponse(JerseyClientImpl.java:438) ~[createsend-java-5.1.3.jar!/:na]
        at com.createsend.util.JerseyClientImpl.handleErrorResponse(JerseyClientImpl.java:426) ~[createsend-java-5.1.3.jar!/:na]
        at com.createsend.util.JerseyClientImpl.post(JerseyClientImpl.java:271) ~[createsend-java-5.1.3.jar!/:na]
        at com.createsend.util.JerseyClientImpl.post(JerseyClientImpl.java:243) ~[createsend-java-5.1.3.jar!/:na]
        at com.createsend.util.JerseyClientImpl.post(JerseyClientImpl.java:218) ~[createsend-java-5.1.3.jar!/:na]
        at com.createsend.Subscribers.addMany(Subscribers.java:96) ~[createsend-java-5.1.3.jar!/:na]

This is the code leading to this exception:

Subscribers subscribersApi = new Subscribers(auth, listId);
SubscribersToAdd sta = new SubscribersToAdd();
// populate sta ...
ImportResult ir = subscribersApi.addMany(sta);  // <---- this throws the exception. The ImportResult is not accessible to parse the errors

Thank you

config.properties not found, if class is not loaded by the main ClassLoader

When the plugin is used in tomcat, the config.properties file is not found. The problem is, that the ClassLoader for tomcat is different from the ClassLoader for the plugin.

The solution, we came up with, is to replace the following in src / com / createsend / util / Configuration.java

Line 36:

properties.load(ClassLoader.getSystemResourceAsStream("com/createsend/util/config.properties"));
TO
properties.load(getClass(). getResourceAsStream("com/createsend/util/config.properties"));

Unable to get useful error information from CreateSendException

If an error occurs during a request (e.g. calling Subscribers.addMany in my case) a CreateSendException is thrown with a message that says:

The CreateSend API responded with the following client error 210: Subscriber Import had some failures. Check resultData for more details

But there are no other properties on the exception object, so no way to actually check "resultData" for more details.

A message body reader for Java class java.lang.String, and Java type class java.lang.String, and MIME media type application/octet-stream was not found

the updates i am sending to campaign monitor using this library work (i'm subscribing and unsubscribing people from lists), but this exception is thrown out during the process:

Nov 14, 2011 3:10:33 PM com.sun.jersey.api.client.ClientResponse getEntity
SEVERE: A message body reader for Java class java.lang.String, and Java type class java.lang.String, and MIME media type application/octet-stream was not found
Nov 14, 2011 3:10:33 PM com.sun.jersey.api.client.ClientResponse getEntity
SEVERE: The registered message body readers compatible with the MIME media type are:
/ ->
com.sun.jersey.json.impl.provider.entity.JSONJAXBElementProvider$General
com.sun.jersey.json.impl.provider.entity.JSONArrayProvider$General
com.sun.jersey.json.impl.provider.entity.JSONObjectProvider$General
com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider$General
com.sun.jersey.json.impl.provider.entity.JSONListElementProvider$General
com.sun.jersey.json.impl.provider.entity.JacksonProviderProxy

where do i register String ?

recipients method in JourneyEmails Java class replaces date param with null value

This causes the date to be set to the default value of the last 30 days (see Campaign Monitor's API Documentation here), instead of the date that is passed in. Where it says (MultivaluedMap)null, it should really say queryString instead, like the methods for getting the number of unsubscribes, bounces, opens, and clicks do for the Journey API.

private PagedResult<JourneyEmailRecipient> recipients(String fromDate, Integer page, Integer pageSize, String orderDirection) throws CreateSendException {
    MultivaluedMap<String, String> queryString = new MultivaluedMapImpl();
    queryString.add("date", fromDate);
    return this.jerseyClient.getPagedResult(page, pageSize, (String)null, orderDirection, (MultivaluedMap)null, new String[]{"journeys", "email", this.journeyEmailID, "recipients.json"});
}

For our project, I created a JourneyEmail Java class that extends the CreateSendBase Java class so that I could override the recipients method and replace the null value with the date that I passed in.

import com.createsend.CreateSendBase;
import com.createsend.models.PagedResult;
import com.createsend.models.journeys.JourneyEmailRecipient;
import com.createsend.util.AuthenticationDetails;
import com.createsend.util.JerseyClientImpl;
import com.createsend.util.exceptions.CreateSendException;
import com.createsend.util.jersey.JsonProvider;
import com.sun.jersey.core.util.MultivaluedMapImpl;
import javax.ws.rs.core.MultivaluedMap;
import java.util.Date;

public class JourneyEmail extends CreateSendBase {
    private final String journeyEmailID;

    public JourneyEmail(AuthenticationDetails auth, String journeyEmailID) {
        this.journeyEmailID = journeyEmailID;
        this.jerseyClient = new JerseyClientImpl(auth);
    }

    public PagedResult<JourneyEmailRecipient> recipients(Date fromDate, Integer page, Integer pageSize, String orderDirection) throws CreateSendException {
        String fromDateStr = JsonProvider.ApiDateFormat.format(fromDate);
        MultivaluedMap<String, String> queryString = new MultivaluedMapImpl();
        queryString.add("date", fromDateStr);
        return this.jerseyClient.getPagedResult(page, pageSize, null, orderDirection, queryString, new String[]{"journeys", "email", this.journeyEmailID, "recipients.json"});
    }
}

May be time for a jersey upgrade

I was getting some errors in my build script about multiple jars in the path having classes with the same full name but different contents. I ran a dependency tree of my project and found that multiple versions of stax-api are getting transitively included.

[info]   | +-com.sun.jersey:jersey-json:1.5
[info]   |   +-com.sun.jersey:jersey-core:1.5
[info]   |   +-com.sun.xml.bind:jaxb-impl:2.2.3
[info]   |   | +-javax.xml.bind:jaxb-api:2.2.2
[info]   |   |   +-javax.activation:activation:1.1
[info]   |   |   +-javax.xml.stream:stax-api:1.0-2
[info]   |   |
[info]   |   +-org.codehaus.jackson:jackson-core-asl:1.5.5
[info]   |   +-org.codehaus.jackson:jackson-jaxrs:1.5.5
[info]   |   | +-org.codehaus.jackson:jackson-core-asl:1.5.5
[info]   |   | +-org.codehaus.jackson:jackson-mapper-asl:1.5.5
[info]   |   |   +-org.codehaus.jackson:jackson-core-asl:1.5.5
[info]   |   |
[info]   |   +-org.codehaus.jackson:jackson-mapper-asl:1.5.5
[info]   |   | +-org.codehaus.jackson:jackson-core-asl:1.5.5
[info]   |   |
[info]   |   +-org.codehaus.jackson:jackson-xc:1.5.5
[info]   |   | +-org.codehaus.jackson:jackson-core-asl:1.5.5
[info]   |   | +-org.codehaus.jackson:jackson-mapper-asl:1.5.5
[info]   |   |   +-org.codehaus.jackson:jackson-core-asl:1.5.5
[info]   |   |
[info]   |   +-org.codehaus.jettison:jettison:1.1
[info]   |     +-stax:stax-api:1.0.1

It looks like the newer version of jersey-json may fix this oopsie, just judging by the POM files. I don't know how feasiable an upgrade would be for you guys, but may be worth looking into.

I'd look into it myself, but your repo is currently down due to the GH maintenance.

Is there something wrong in the active() method?!?

I have spent the last few days trying to figure out why I am having so much difficulty with the active() method in the Lists class. Judging from the samples I should not be having so much difficulty

sendDate ignores hour

When calling send on a Campaigns instance the provided Date sendDate parameter gets stripped of the time.
It will always fall back to 12:00 AM.

Access Denied

When I try to download createsend-java-1.0.2.jar, I get an Acess Denied message.

Jersey 2.x migration

Hey guys,
Could we expect to have it working with jersey 2.x version sometimes in near future?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.